Two checkpoint-adjacent parameters paired by alphabetical proximity rather than topical kinship. checkpoint_flush_after is the third of the four *_flush_after writeback parameters; checkpoint_warning is a logging knob that emits a complaint when checkpoints fire too frequently. Different jobs, different audiences, but neither needs 400 words of its own.
checkpoint_flush_after
The writeback-tour sibling from backend_flush_after. Same mechanism — sync_file_range()-based hints to the kernel to start writing back recently-dirtied pages rather than let them accumulate in the page cache. Same motivation: prevent the gigabytes-of-buffered-writes-drained-all-at-once-during-fsync failure mode that uncontrolled kernel writeback produces.
Default is 256kB on Linux, 0 elsewhere. Range 0 to 2MB. Context same as the other checkpoint parameters: postgresql.conf or command line, sighup to reload.
The 256kB default is notably smaller than bgwriter_flush_after’s 512kB. The reason: the checkpointer is the most aggressive of the writers — it’s draining the entire dirty portion of shared_buffers across the spread interval governed by checkpoint_completion_target — and tighter writeback hints help the kernel keep up with that volume without letting too much accumulate. The defaults table from backend_flush_after, for reference:
| Parameter | Linux default |
|---|---|
backend_flush_after |
0 (disabled) |
bgwriter_flush_after |
512kB |
checkpoint_flush_after |
256kB |
wal_writer_flush_after |
1MB |
Tuning is rare. The default is well-calibrated for typical hardware. Raise toward 512kB on very fast NVMe where larger writeback batches don’t cause stalls; lower toward 128kB if your monitoring shows query-latency spikes correlated with checkpoint activity that don’t go away after the checkpoint_timeout / completion_target tuning from the previous post.
Recommendation: Leave at 256kB on Linux. This is the parameter in the writeback family that benefits most from its default, and the one you’re least likely to need to touch.
checkpoint_warning
A pure logging parameter. If two checkpoints occur within checkpoint_warning seconds of each other due to max_wal_size pressure (not because of checkpoint_timeout), PostgreSQL logs a message suggesting you increase max_wal_size. Default is 30s. Set to 0 to disable. Context is sighup.
The intent is to catch the misconfiguration where max_wal_size is so small that the WAL-volume trigger fires constantly, defeating the purpose of checkpoint_timeout. The log message is exactly that suggestion:
1 LOG: checkpoints are occurring too frequently (12 seconds apart)
2 HINT: Consider increasing the configuration parameter "max_wal_size".
This is the canonical diagnostic for the failure mode I described in the previous post: when pg_stat_bgwriter.checkpoints_req dominates checkpoints_timed, checkpoint_warning is what makes the problem visible in the log. It doesn’t fix anything — it just complains, with a correct and actionable suggestion.
A few notes:
- It only fires for
req-triggered checkpoints. Time-triggered checkpoints firing every 30 seconds wouldn’t produce the warning, butcheckpoint_timeouthas a 30-second minimum, so that case is unreachable through normal configuration anyway. - It can be misleading on PITR restore or bulk-load operations, both of which legitimately produce checkpoint storms while they’re running. The log noise is harmless but worth recognizing for what it is.
- It pairs naturally with
log_checkpoints, which (defaulting toonsince PG 15) logs every checkpoint with full statistics.checkpoint_warninggives you the alert;log_checkpointsgives you the evidence to diagnose it.
Recommendation: Leave at 30s. The default is correct, the log noise is minimal when things are healthy, and the warning is genuinely useful when things aren’t. If the warning starts firing in your logs, the answer is almost certainly to raise max_wal_size, not to silence the warning. The parameter exists to be helpful; the only operators who disable it are the ones who have decided they don’t want to know.