Skip to main content
RunBook Academy

← All checklists in PostgreSQL

Monthlypg-backup-readiness

PostgreSQL Backup Readiness Review

20 items ·11 critical ·9 warn ·0 info

How to use this review

Monthly. It has one item that matters and eighteen that describe the conditions under which that item is meaningful.

The failure this review is designed to catch

Record the restore time, not just the result

The recovery time objective in the disaster-recovery document is a claim. The duration of the restore you performed this month is a measurement, and the two are frequently different numbers.

Report the comparison either way. A restore that takes eleven hours against a four-hour objective is a capability gap that belongs to the service owner, and it can only be reported by somebody who has measured it.

What a dump does not contain

Absent from pg_dump <database>Comes from
Roles and role membershipspg_dumpall --globals-only
Tablespace definitionspg_dumpall --globals-only
Other databasesA dump per database
Extension codeThe target cluster’s packages
Any point-in-time capabilityPhysical backup plus WAL archiving

A restore without the globals fails at the first GRANT — late, after the schema and usually after the data, which is the most expensive moment to discover it.

Two artefacts, two capabilities

A physical backup restores faster and supports point-in-time recovery. A logical dump restores into a different major version and can restore a single table.

An estate with only one of them has a recovery capability, and it is probably not the one described in its documents. Say which you have.

Where the numbers come from

Backup age and success come from the backup tool’s own record and from the destination listing, because a job that reports success and writes nothing is the failure this review exists to catch. Archive health comes from pg_stat_archiverfailed_count, last_failed_wal, and the age of last_archived_time.

The restore duration is measured, not estimated: from the moment the procedure starts to the moment the application’s own query returns correct results. That number, and not a calculation, is what the recovery time objective is compared against.

Access this needs

Read access to the backup destination and its retention configuration, and enough capacity on a non-production host to actually perform the restore this checklist requires. That host is the point of the review; without it most items cannot be completed, which is itself the finding.

A role holding pg_monitor on the source cluster for the archiver and size figures, and the credentials the restore procedure itself names.

The restore must be run by somebody who did not write the runbook, at least once in every two review periods, which means their access has to exist before the review rather than being arranged during it.

What the review produces

A dated record naming the reviewer, the backup taken, the host it was restored onto, the measured duration of each phase, and the comparison against the recovery time objective. Attach the row counts compared against the source, the pg_verifybackup output, and the query run as the application’s role rather than as a superuser.

Any place where the written runbook was wrong is a finding in its own right and goes back into the runbook the same day. A restore rehearsal that produced no corrections has usually tested the wrong things.

Sign-off

  • Reviewer: ________________ Date: ___________
  • Database owner: ___________ Date: ___________
  • Service owner: ____________ Date: ___________

Every critical item must pass. A failing critical item is a blocker, not a note for the next sprint: record the date, the reviewer, the disposition of every item that did not pass, and the name of whoever accepted the residual risk.

Critical11 items

  1. psql -c "SELECT relkind, count(*) FROM pg_class WHERE relkind IN ('r','i','S','v','m') GROUP BY 1 ORDER BY 1;"
  2. set -o pipefail
  3. psql -c "SELECT pg_switch_wal();"
  4. psql -c "SELECT archived_count, last_archived_wal, last_archived_time, failed_count, last_failed_time FROM pg_stat_archiver;"

Warning9 items

  1. psql -c "SELECT pg_size_pretty(sum(pg_database_size(datname))) FROM pg_database;"
  2. psql -c "SELECT slot_name, active, wal_status FROM pg_replication_slots;"