PostgreSQLXII · WAL, Checkpoints and Crash RecoveryWAL
Crash recovery: what "consistent state" means
What you'll learn
- Read a crash recovery log and say what each line means
- Estimate recovery time from checkpoint distance and replay rate
- Distinguish a normal recovery from one that is genuinely failing
- Use pg_controldata to establish a stopped cluster's state
Prerequisites
Verified against PostgreSQL 18.x · PostgreSQL (comparison targets) 17.11, 16.15 · PostgreSQL (support calendar) 18, 17, 16, 15, 14 supported · pgBackRest 2.59.1 · PgBouncer 1.25.2 · Patroni 4.1.5 · Ubuntu (host baseline) 26.04 LTS · 2026-08-27
Crash recovery is not an exceptional path. It is the same code that runs on every standby continuously, and it runs on the primary any time the cluster was not shut down cleanly.
What it does
- Read
pg_controlto find the last checkpoint’s redo location. - Replay every WAL record from there forward.
- Stop when a record is not valid — that is the end of the log.
- Take a checkpoint.
- Accept connections.
Committed transactions are replayed and become visible. Uncommitted ones were never visible and remain so. Nothing is rolled back, because nothing needs to be: from lesson VII-01, an aborted transaction’s versions are simply never visible to anyone.
The log, line by line
$ docker kill --signal=KILL rbpg-stor && docker start rbpg-storLOG: database system was interrupted; last known up at 2026-08-27 21:01:01 UTC
LOG: database system was not properly shut down; automatic recovery in progress
LOG: redo starts at 7/CB35CEA8
LOG: invalid record length at 7/CF4461A0: expected at least 24, got 0
LOG: redo done at 7/CF446178 system usage: CPU: user: 0.09 s, system: 0.03 s, elapsed: 0.12 s
LOG: checkpoint starting: end-of-recovery immediate wait
LOG: checkpoint complete: wrote 6003 buffers (36.6%), wrote 2 SLRU buffers; 0 WAL file(s) added, 4 removed, 0 recycled; write=0.026 s, sync=0.018 s, total=0.066 s; sync files=9, longest=0.013 s, average=0.002 s; distance=66468 kB, estimate=66468 kB; lsn=7/CF4461A0, redo lsn=7/CF4461A0
LOG: database system is ready to accept connections$ psql -U postgres -At -c "SELECT count(*) FROM crashtest"300000| Line | Meaning |
|---|---|
was interrupted; last known up at | The control file was not marked shut down |
was not properly shut down; automatic recovery in progress | Recovery is starting |
redo starts at 7/CB35CEA8 | The last checkpoint’s redo location |
invalid record length … got 0 | The end of the WAL. Normal. |
redo done at 7/CF446178 … elapsed: 0.12 s | Replay finished, with timing |
checkpoint starting: end-of-recovery immediate wait | Establishing a new recovery point |
database system is ready to accept connections | Done |
Estimating recovery time
Measured here: 65 MB replayed in 0.12 seconds of elapsed time. That is this hardware, warm cache, a simple insert workload — but the method generalises:
recovery time ≈ WAL to replay ÷ replay rate
WAL to replay ≈ up to max_wal_size, or checkpoint_timeout × generation rate
pg_controldata
The authoritative state of a cluster that is not running.
$ pg_controldata "$PGDATA"pg_control version number: 1800
Catalog version number: 202506291
Database system identifier: 7678780827444375601
Database cluster state: in production
pg_control last modified: Thu 27 Aug 2026 09:01:28 PM UTC
Latest checkpoint location: 7/D327F4D8
Latest checkpoint's REDO location: 7/D327F4D8
Latest checkpoint's REDO WAL file: 0000000100000007000000D3
Latest checkpoint's TimeLineID: 1
Latest checkpoint's PrevTimeLineID: 1
Latest checkpoint's full_page_writes: on
Latest checkpoint's NextXID: 0:848603
Latest checkpoint's NextOID: 27921
Latest checkpoint's NextMultiXactId: 4| Field | Use |
|---|---|
Database cluster state | shut down is clean; in production on a stopped cluster means it crashed |
Latest checkpoint's REDO location | Where recovery will start |
Latest checkpoint's REDO WAL file | The earliest segment that must exist |
Database system identifier | Identifies the cluster lineage. Must match between a primary and its standbys |
Latest checkpoint's TimeLineID | Which timeline. Relevant after any promotion |
Latest checkpoint's REDO WAL file is the precise answer to “which WAL
files do I still need” for crash recovery — that file and everything
after it. It is not the answer for archiving or replication, which
retain from their own positions.
Clean shutdown, for contrast
$ docker stop rbpg-stor && docker start rbpg-storLOG: starting PostgreSQL 18.6 (Debian 18.6-1.pgdg13+2) on x86_64-pc-linux-gnu
LOG: listening on IPv4 address "0.0.0.0", port 5432
LOG: database system was shut down at 2026-08-27 21:01:27 UTC
LOG: database system is ready to accept connectionsdatabase system was shut down at versus database system was interrupted; last known up at is how you determine, after the fact,
whether the last stop was clean. It is the first line to look for in a
post-incident log review.
What to take from this
- Recovery replays from the last checkpoint’s redo location to the end of the WAL, then checkpoints.
invalid record length … got 0atLOGlevel beforeredo doneis the normal end marker, not corruption.- Measured: 300,000 rows survived a SIGKILL; 65 MB replayed in 0.12 s.
- Measure your own replay rate on a copy, and make the
max_wal_sizedecision against it. pg_controldata’s cluster state and REDO WAL file are the first two fields to read on a stopped cluster.- Replay is serial. More cores do not help; storage latency and
recovery_prefetchdo.
Cross-course references
- Linux for Production Sysadmins — Part VIII (Logging and journald) covers capturing the redo log lines before they rotate, and Part LXXXII (Root cause analysis) covers establishing what caused the crash rather than being satisfied that recovery worked.
- Docker & Containers — Part VI (Container lifecycle) covers the stop-then-kill sequence that makes a crash the normal case for a containerised cluster.
Quiz
Knowledge check · 6 questions
Q1. A standby is 40 GB behind in replay and the primary has failed. What dominates the time to bring the standby into service?
Q2. A cluster that would not start shows 'Database cluster state: in production' in pg_controldata. What does that tell you?
Q3. Which of these log lines during recovery indicates a genuine failure rather than normal completion?
Q4. Which factors make WAL replay slower than the original write path? Select all that apply.
Q5. Crash recovery must roll back uncommitted transactions before the cluster can accept connections.
Q6. How would you establish what a crash costs your cluster in recovery time, and what decision does that number inform?
Passing score: 75%. Answers are checked in this browser.