Backups you can restore from
A backup is a copy of the past. Recovery means taking back exactly what was lost, without undoing what happened since.
What a dump is
pg_dump connects like any client and reads the database inside one transaction, so the dump is a consistent snapshot of that moment. The custom format (-Fc) is compressed and lets pg_restore choose what to restore and in which order. A dump says nothing about what happened after it was taken. If the nightly dump runs at 01:00 and the damage happens at 01:20, everything written between 01:20 and now exists only in the live database. Physical backups with archived WAL let you replay to any moment, but they restore a whole cluster, which is rarely what you want for one bad statement.
Restore somewhere else first
Restoring a dump over a live database with pg_restore --clean makes the database match the dump. That brings back the lost rows and also deletes every later write and resets sequences, so new inserts may collide with ids handed out since. The safer pattern:
createdb recoveryandpg_restore -d recovery waybill.dump. Nothing live is touched.- Compare: which ids exist in the backup but not in production?
- Decide which of those were lost by mistake, then copy only them back, keeping their original ids. Other tables, logs, and customers refer to those ids.
Read what the change meant
The hardest part is step 3. A bad migration usually deleted some rows on purpose and others by accident. SQL evaluates AND before OR, so status = 'cancelled' AND created_at < X OR depot = 'depot-3' means (cancelled and old) or depot-3, whatever the comment above it says. Write down the rule the change was supposed to apply, express it as a condition, and exclude rows that match it from what you restore. Then verify by counting: rows restored, rows still purged, rows written since the backup, all matching what you expected before you started.
A backup you have never restored from is a hope. Practise the restore, time it, and write it down, so the first time is not during an incident.
Key terms
- Logical backup
- A dump of the database as SQL or an archive of rows, taken from a consistent snapshot (pg_dump).
- Point-in-time recovery
- Restoring a physical base backup and replaying archived WAL up to a chosen moment.
- RPO
- Recovery point objective, the most data you can afford to lose, measured in time.
- Selective restore
- Recovering only some objects or rows from a backup into a live system.
Read further
- PostgreSQL Documentation, version 17, Chapter "Backup and Restore", sections "SQL Dump" and "Continuous Archiving and Point-in-Time Recovery (PITR)" (Free online (PostgreSQL Licence))
What pg_dump guarantees (a consistent snapshot), and what PITR adds (recovery to any moment). - PostgreSQL Documentation, version 17, Reference pages for pg_dump and pg_restore (Free online (PostgreSQL Licence))
Custom-format archives,-lto list contents,-tto pick a table,--data-only, and why--cleanagainst a live database is dangerous. - Database Reliability Engineering, Chapter "Backup and Recovery" (Paid (book or O'Reilly subscription))
Recovery as the goal of backups, recovery scenarios, and testing restores before you need them. - PostgreSQL Documentation, version 17, Chapter "SQL Syntax", section "Operator Precedence" (Free online (PostgreSQL Licence))
Why AND binds tighter than OR, the bug behind many bad WHERE clauses.