Article
Why HA Does Not Make a Long PostgreSQL checkpoint_timeout Safe
A longer PostgreSQL checkpoint_timeout can increase WAL replay exposure not only on the primary but also when a standby restarts. This article explains why HA is not a substitute for recovery-time control and connects checkpoints, restartpoints, monitoring, and failure drills into one availability decision.
Share
Koharu's reading tip
Let’s separate failover availability from restart recovery and decide whether a replica really justifies a longer checkpoint interval.

If a primary with checkpoint_timeout stretched to 45 minutes fails, promoting a standby appears to avoid waiting for the primary to recover. In an HA design, that can make a longer interval look safer than it really is.
That reasoning holds only while the failover target keeps running. If the promoted standby also has to restart, the long checkpoint interval returns as a recovery concern.
A post published on August 12, 2026 raises exactly this second-failure question. Following the checkpoint and restartpoint mechanism shows why checkpoint_timeout should be chosen against an availability objective, not performance in isolation.
A longer checkpoint interval widens the potential REDO window
PostgreSQL records changes in WAL before the corresponding data files are updated. At a checkpoint, dirty pages are flushed and PostgreSQL records the position from which REDO can begin after a crash. The mechanism is described in the PostgreSQL 18 WAL configuration documentation.
In PostgreSQL 18, checkpoint_timeout defaults to five minutes and accepts values from 30 seconds to one day. Automatic checkpoints start when that time is reached or when WAL approaches max_wal_size. The official parameter reference explicitly notes that increasing either setting can increase crash-recovery time.
This is not a promise that a five-minute timeout produces recovery within five minutes. Actual time depends on the WAL that must be replayed, storage, CPU, and the work represented by the WAL. The source post likewise cautions that startup and replay can exceed checkpoint_timeout; the setting is better understood as controlling how often a new recovery starting point can be established.
Standby restartpoints depend on checkpoint records from the primary
A physical standby receives and continuously applies the same WAL stream generated by the primary. According to the official standby operation documentation, a restarted standby replays available WAL and searches the archive, local pg_wal, and then streaming replication as necessary.
The standby equivalent of a checkpoint is a restartpoint. It records how far recovery has progressed so that already-processed WAL does not need to be scanned again, but it can only be created at a checkpoint record generated upstream. The WAL configuration documentation therefore says that restartpoints cannot occur more frequently than checkpoints on the primary.
At the same time, a running standby can be promoted with pg_promote(), and the PostgreSQL 18 administration functions can wait for promotion to complete. When only the primary fails and the standby remains healthy, HA can restore service without waiting for the failed primary to replay WAL.
The gap appears when the promoted node subsequently restarts. A host failure, a mistaken rolling-restart sequence, or a fault reproduced by the same workload can restart the nodes one after another. The former standby then replays from its available restartpoint. HA provides another live node to move to; it does not erase restart cost on both nodes.
Choose checkpoint_timeout from both write load and RTO
The answer is not simply to make checkpoint_timeout as short as possible. More frequent checkpoints can reduce the WAL that must be redone, but they also flush dirty buffers more often. With full_page_writes enabled, the first change to a page after each checkpoint also produces a full-page image. The official WAL guidance describes this tradeoff between faster crash recovery and additional I/O.
PostgreSQL 18 defaults checkpoint_completion_target to 0.9, spreading checkpoint writes across most of the available interval. Before lengthening the interval, it is useful to determine whether that smoothing is working and whether checkpoints requested by pressure on max_wal_size are the real issue.
The source post recommends keeping the robust starting point of the five-minute default. Official documentation does not prohibit tuning, but it does state the recovery consequence of increasing the interval. A defensible change therefore needs two pieces of evidence: an observed write-I/O benefit and a recovery result that remains within the required RTO.
PostgreSQL 17 and later expose both sides in pg_stat_checkpointer
Capture current settings and cumulative statistics before changing them. On PostgreSQL 17 and later, the following query exposes checkpoint and restartpoint counts along with write and synchronization time.
SHOW checkpoint_timeout;
SHOW checkpoint_completion_target;
SHOW max_wal_size;
SHOW log_checkpoints;
SELECT
num_timed,
num_requested,
num_done,
restartpoints_timed,
restartpoints_req,
restartpoints_done,
write_time,
sync_time,
buffers_written,
stats_reset
FROM pg_stat_checkpointer;
pg_stat_checkpointer was introduced in PostgreSQL 17, when checkpoint-related columns were moved out of pg_stat_bgwriter. The PostgreSQL 18 view definition also distinguishes requested or timed restartpoints from restartpoints_done, because a restartpoint request can be skipped. Compare deltas over a known interval rather than reading a single cumulative value in isolation.
PostgreSQL 16 and earlier use a different view layout. Checkpoint counts and durations are available from the older pg_stat_bgwriter definition, while restartpoints should also be examined in server logs. In current PostgreSQL, log_checkpoints is on by default and logs checkpoints and restartpoints with write volume and timing information.
SELECT
checkpoints_timed,
checkpoints_req,
checkpoint_write_time,
checkpoint_sync_time,
buffers_checkpoint,
stats_reset
FROM pg_stat_bgwriter;
Replication lag is a separate axis. If a standby has not received or replayed the current WAL, checkpoint interval alone cannot describe recovery readiness. Following the streaming-replication monitoring guidance, observe pg_stat_replication on the primary and pg_last_wal_receive_lsn() plus pg_last_wal_replay_lsn() on the standby as well.
Test a restart after failover before accepting the change
A validation plan for a longer checkpoint_timeout should include failure paths, not only steady-state I/O. Under representative WAL generation, measure primary failure to standby promotion separately from the time required for the promoted node to restart and accept connections. Those measurements separate the delay HA can absorb from the delay it cannot.
Rolling-restart automation deserves the same review. It should stop before restarting another node when the first one misses its recovery deadline, recognize which node has been promoted, and define clear stop conditions for manual intervention. PostgreSQL configuration alone cannot provide these orchestration safeguards.
Managed PostgreSQL services differ in which settings, failover controls, logs, and statistics they expose. Even when the SQL above is not directly available, the decision remains the same: use the provider-specific tools to measure WAL replay and restart readiness on both the primary and standby.
An HA replica is therefore not a safety net for an arbitrarily long checkpoint_timeout. It handles the first failure while another node remains live, but a second restart returns the system to the same WAL history and restartpoint constraints. Moving away from the default is justified only when the performance evidence and a two-stage recovery drill both satisfy the RTO.
Source
- Title: Jeremy Schneider: Postgres Checkpoint Followup and Collation Visualization and Codex Luna
- URL: https://postgr.es/p/9s8
Share
Related Articles
These articles share nearby categories or tags, so you can keep reading along the same thread.




