Skip to main content
RunBook Academy

PostgreSQLXIII · Backup, Archiving and Point-in-Time RecoveryBackup

pg_basebackup: its role and its limits

Intermediate⏱ ~35 min🧪 Lab requiredpg_basebackuppg_verifybackuppg_combinebackup

What you'll learn

  • Take a base backup with the flags that matter and know why each is there
  • Verify a backup with pg_verifybackup and its manifest
  • Take and reconstruct an incremental backup
  • State what pg_basebackup cannot do

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

Not yet marked complete on this device.

pg_basebackup is the low-level API from the previous lesson, driven correctly by a program that holds one connection open, copies the right files, excludes the right files, and writes backup_label. It ships with PostgreSQL and it is the right starting point for physical backups.

Taking one

Read-only / Safea base backup, compressed, with its own WAL
$ pg_basebackup -D /backup/base -Ft -z -Xstream -P -c fast
waiting for checkpoint
23854/23854 kB (100%), 0/1 tablespace
23854/23854 kB (100%), 1/1 tablespace
Read-only / Safewhat it produced
$ ls -la /backup/base/
-rw------- 1 postgres postgres  138651 backup_manifest
-rw------- 1 postgres postgres 3162227 base.tar.gz
-rw------- 1 postgres postgres   17091 pg_wal.tar.gz

Three artefacts, and all three matter.

FileWhat it isIf you lose it
base.tar.gzThe data directoryNo backup
pg_wal.tar.gzWAL generated during the backupBackup cannot reach consistency
backup_manifestChecksums of every fileNothing to verify against

The flags that matter

-X stream (the default) opens a second connection and streams WAL alongside the copy, so the backup contains everything it needs to reach a consistent state on its own. The alternative, -X none, produces a backup that is unusable without the WAL archive. That is a legitimate choice when you have a reliable archive, and a common way to end up with an unrestorable backup when you do not.

-c fast requests an immediate checkpoint. Without it the backup waits for a spread checkpoint, which on a busy cluster with a large checkpoint_timeout can be several minutes of doing nothing. fast costs a burst of I/O, exactly as lesson XII-04 described.

-P shows progress. On a multi-hour backup this is the difference between knowing it is working and hoping.

-Ft -z produces compressed tar files. -Fp produces a plain directory — larger, and the format pg_combinebackup needs.

--checkpoint=spread is the polite option for a cluster where a burst of checkpoint I/O would be noticed. It trades backup start latency for a gentler write pattern.

-R writes standby.signal and the connection settings, turning the backup into a standby. Part XIV uses this.

Verifying

Read-only / Safepg_verifybackup against the manifest
$ pg_verifybackup -n /tmp/vb
backup successfully verified

The manifest lists every file with its size and checksum. Verification detects truncation, corruption in transit, and files that went missing between backup and storage. It does not prove the backup restores — only that the bytes are the bytes that were written. Proving a restore is lesson XIII-08.

Incremental backup

PostgreSQL 17 added incremental base backups, and they are the largest change to native backup capability in years. The prerequisite is WAL summarization.

Configuration changeenabling WAL summarization
$ ALTER SYSTEM SET summarize_wal = on; SELECT pg_reload_conf();
     name      | setting |       source
---------------+---------+--------------------
summarize_wal | on      | configuration file

With summarization on, an incremental backup takes the previous backup’s manifest as its baseline:

Read-only / Safefull, then incremental after updating 2,000 of 400,000 rows
$ pg_basebackup -D /backup/full -Fp -Xstream -c fast -P
# ... 2,000 rows updated, CHECKPOINT ...
pg_basebackup -D /backup/incr -Fp -Xstream -c fast -i /backup/full/backup_manifest -P
130846/130846 kB (100%), 1/1 tablespace      <- full
5189/131307 kB (3%),   1/1 tablespace      <- incremental

$ du -sh /backup/full /backup/incr
144M    /backup/full
24M     /backup/incr

Three per cent of the cluster sent. Unchanged blocks are replaced by stub files:

Read-only / Safethe stubs an incremental backup leaves behind
$ find /backup/incr -name 'INCREMENTAL.*' | wc -l
671
Read-only / Safereconstructing and verifying the chain
$ pg_combinebackup /backup/full /backup/incr -o /backup/merged
pg_ctl -D /backup/merged start
psql -p 5434 -c "SELECT count(*), count(*) FILTER (WHERE pad LIKE 'z%') FROM bulk"
$ du -sh /backup/merged
145M    /backup/merged

server started

rows  | updated_rows
--------+--------------
400000 |         2000

All 400,000 rows, and the 2,000 updated after the full backup carry their new values. The chain reconstructed correctly.

What pg_basebackup cannot do

  • Back up a single database or table. It copies the whole cluster.
  • Deduplicate across backups. Each full backup is a full copy.
  • Manage retention. No expiry, no rotation, no catalogue.
  • Parallelise the copy. One connection, one stream. On a very large cluster this is the practical ceiling.
  • Encrypt. Compression, yes. Encryption is your problem.
  • Resume. An interrupted backup starts over.
  • Restore. There is no pg_baserestore. Restoring is extracting the archive and configuring recovery yourself.

That list is the argument for the tools in lesson XIII-08. It is not an argument against pg_basebackup, which is correct, always present, and the right answer for a great many clusters.

What to take from this

  • pg_basebackup drives the low-level API correctly. Prefer it to hand-rolled scripts.
  • -X stream makes the backup self-sufficient; -X none makes it depend on your archive.
  • Keep backup_manifest with the backup, and run pg_verifybackup.
  • Incremental backups need summarize_wal, and sent 3% — 24 MB against 144 MB — in a measured case.
  • An incremental is not a data directory. pg_combinebackup reconstructs it, and every member of the chain must survive.
  • No deduplication, no retention, no parallelism, no encryption, no resume, and no restore command.

Cross-course references

  • Linux for Production Sysadmins — Part XLVII (Backup strategy) covers retention arithmetic, which changes shape once a backup chain has dependent members rather than independent fulls.
  • Observability for Production Sysadmins — Part XCI (Backup strategy) covers alerting on the age of the oldest usable full, which is the number an incremental chain makes non-obvious.

Quiz

Knowledge check · 6 questions

  1. Q1. A nightly pg_basebackup uses -X none. The WAL archive has been silently failing for a week. What is the state of those seven backups?

  2. Q2. A backup chain is one weekly full plus six nightly incrementals. Tuesday's incremental is lost to a storage fault. What can still be restored?

  3. Q3. Incremental backups were enabled six months ago with wal_summary_keep_time left at its default. A monthly full plus daily incrementals is proposed. What breaks?

  4. Q4. Which of these does pg_basebackup NOT do? Select all that apply.

  5. Q5. Attempting to start an incremental backup directory as a cluster fails with a clear error rather than producing a partially populated database.

  6. Q6. How does WAL summarization enable incremental backups, and what does it cost?

Passing score: 75%. Answers are checked in this browser.