PostgreSQLXIII · Backup, Archiving and Point-in-Time RecoveryBackup
Logical backups: pg_dump, pg_restore, scope and limits
What you'll learn
- Choose a dump format from what the restore needs to do
- State precisely what pg_dump does and does not capture
- Restore selectively, in parallel, and with the right ordering
- Recognise where a logical backup is the wrong tool
Prerequisites
Practice
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
A logical backup captures the contents of a database as statements that rebuild it, rather than the bytes on disk. That difference gives it capabilities a physical backup does not have, and limits a physical backup does not have either.
Formats
| Format | Flag | Restore with | Selective | Parallel | Compressed | Integrity |
|---|---|---|---|---|---|---|
| Plain | -Fp | psql | No | No | External only | None |
| Custom | -Fc | pg_restore | Yes | Yes | Built in | Yes |
| Directory | -Fd | pg_restore | Yes | Dump and restore | Built in | Yes |
| Tar | -Ft | pg_restore | Yes | No | External only | Yes |
$ pg_dump -U postgres -F c -f /tmp/d.dump postgres && pg_dump -U postgres -F p -f /tmp/d.sql postgres && ls -la /tmp/d.dump /tmp/d.sql-rw-r--r-- 1 postgres postgres 751359 /tmp/d.dump
-rw-r--r-- 1 postgres postgres 2156673 /tmp/d.sql$ pg_restore -l /tmp/d.dump;
; Archive created at 2026-08-27 21:26:07 UTC
; dbname: postgres
; TOC Entries: 7
; Compression: gzip
; Dump Version: 1.16-0
; Format: CUSTOM
; Dumped from database version: 18.6 (Debian 18.6-1.pgdg13+2)
; Dumped by pg_dump version: 18.6 (Debian 18.6-1.pgdg13+2)
;What pg_dump does not capture
From lesson XIII-01, measured: zero role or tablespace definitions.
The complete list of what a pg_dump of one database omits:
- Roles and their passwords.
pg_dumpall --globals-only. - Tablespace definitions. Same.
- Other databases. One dump per database.
postgresql.confandpg_hba.conf. Files, not catalogue.- WAL, and therefore any point in time. A dump is one instant.
- Physical layout. Indexes are rebuilt, not copied.
pg_statcounters and statistics. The restored database needsANALYZE.
That last one is easy to overlook and expensive: a freshly restored
database has no planner statistics, which lesson VIII-07 measured as
worth 1,003 buffers against 4 on one query. pg_restore does not run
ANALYZE for you.
# after every logical restore
vacuumdb --analyze-only --jobs=8 --dbname=restored
Restoring
# whole database, parallel, into a fresh database
createdb restored
pg_restore -d restored --jobs=8 /tmp/d.dump
# schema first, inspect, then data
pg_restore -d restored --schema-only /tmp/d.dump
pg_restore -d restored --data-only --jobs=8 /tmp/d.dump
# one table
pg_restore -d restored --table=orders /tmp/d.dump
# generate SQL without applying it, to read what would happen
pg_restore --file=would_do.sql /tmp/d.dump
Where logical backups are the right tool
Cross-version migration. A dump from 15 restores into 18. Physical backups cannot cross major versions at all.
Cross-platform migration. Different architecture, different operating system, different page layout. A dump is portable; a physical backup is not.
Selective recovery. Restoring one table from a 4 TB cluster without restoring the other 3.99 TB.
Schema extraction. --schema-only produces a readable, diffable
definition.
Small databases, where a dump-and-restore is quick enough that the extra capability of PITR is not worth its complexity.
Where they are the wrong tool
Anything large. A dump reads every row through the SQL layer and a restore rebuilds every index. For a 4 TB database this is hours to days; a physical restore is a file copy.
Any RPO shorter than the dump interval. A dump is a single instant. Nightly dumps mean a 24-hour RPO, and no amount of care changes that.
A running system’s consistency across databases. pg_dumpall dumps
each database in its own transaction, so two databases are not captured
at the same instant.
What to take from this
- Custom or directory format for anything you intend to restore. Plain format has no integrity check, and corruption is found mid-restore.
- Measured: 751 kB custom against 2,157 kB plain, and a corrupted custom dump rejected before restore.
pg_dumpomits roles, tablespaces, configuration files and statistics. Takepg_dumpall --globals-onlyalongside, andANALYZEafterwards.pg_restorecontinues past errors by default. Use--exit-on-erroror check deliberately.- Directory format supports
--jobson the dump as well as the restore. - A dump holds a snapshot for its whole duration, with every consequence from lesson VII-05.
Cross-course references
- Linux for Production Sysadmins — Part XLVIII (Backup tools) covers the pipe-and-exit-status trap that makes a logical dump appear to have succeeded, and Part XLIX (Restore) covers proving the output is usable.
- Git, CI/CD & GitOps — Part XXXV (Secrets in Git) covers the globals dump, which contains role passwords and is the file most often committed by accident.
Quiz
Knowledge check · 6 questions
Q1. A nightly pg_dump of a 500 GB database takes six hours. Tables on that cluster have been growing steadily despite healthy autovacuum. What is the connection?
Q2. Why can pg_dump -Fc not be combined with --jobs, while pg_dump -Fd can?
Q3. A restore log ends with 'errors ignored on restore: 412' and the database is in use the next morning. What went wrong procedurally?
Q4. Which are genuine advantages of a logical backup over a physical one? Select all that apply.
Q5. A freshly restored logical backup needs ANALYZE run against it before its query performance is representative.
Q6. When is a logical backup the right tool, and when is it the wrong one?
Passing score: 75%. Answers are checked in this browser.