Three open source tools cover most self-managed PostgreSQL physical backups: pgBackRest, Barman, and WAL-G. All three take base backups, archive write-ahead log (WAL), and restore to a point in time. They differ in where they run, how they find changed data, and which Kubernetes operators ship them. In 2026 there is also a maintenance question. On 27 April 2026 pgBackRest's maintainer announced the project was no longer maintained, and on 18 May a group of sponsors funded it again. This guide compares pgBackRest 2.60.0, Barman 3.20.1, and WAL-G v3.0.9, including PostgreSQL 17 native incremental backup, and ends with a choice by scenario.
- All three are maintained as of November 2026: pgBackRest 2.60.0 (MIT), Barman 3.20.1 (GPL-3.0), and WAL-G v3.0.9 (Apache 2.0).
- Barman is the one that drives PostgreSQL 17's native incremental backup (
pg_basebackup --incremental). pgBackRest and WAL-G use their own incremental mechanisms. - Barman centers on a dedicated backup server, pgBackRest on a repository (local, remote host, or object storage), and WAL-G on an agent that pushes to object storage.
- On Kubernetes the operator decides: CloudNativePG uses the Barman Cloud Plugin, Crunchy PGO and the Percona Operator use pgBackRest, and Zalando's Spilo uses WAL-G.
- Treat backups as unproven until a scheduled point-in-time restore drill has worked.
Scope and review date: November 2026. This post covers pgBackRest 2.60.0, Barman 3.20.1, WAL-G v3.0.9, and CloudNativePG 1.30, with PostgreSQL 14 to 18. Versions, defaults, and commands were checked against each project's documentation and release notes on 9 November 2026. They were not run in a lab, so rehearse every command on a staging cluster. There is no speed comparison here because none of the projects publishes one we can cite.
Are pgBackRest, Barman, and WAL-G still maintained in 2026?
Yes, all three. pgBackRest had a gap. On 27 April 2026 the pgBackRest news page posted "pgBackRest Is No Longer Being Maintained". Percona's account says the maintainer's sponsorship ended after the Crunchy Data acquisition. On 18 May 2026 the project announced "pgBackRest Will Continue!", funded by Amazon Web Services, Supabase, pgEdge, Tiger Data, Percona, and Eon.io. Five releases followed, from 2.59.0 (20 July 2026) to 2.60.0 (18 October 2026).
Barman is developed in EDB's GitHub organization. Its 3.20.1 release (29 September 2026) fixes CVE-2026-93853, a privilege escalation that could delete unrelated cloud snapshots. WAL-G's latest releases are v3.0.8 (21 January 2026) and v3.0.9 (20 August 2026).
# Record the installed version on every database and backup host
pgbackrest version
barman --version
wal-g --versionInterpretation: if pgBackRest reports a version before 2.59.3 and your repository is encrypted, upgrade. A 4 October 2026 notice says earlier versions did not check for an error when generating random data for encryption subkeys and salts.
From 2.59.0, only the restore command runs as root by default. From 2.60.0, restore stops with an error when a restored file has an invalid page checksum, and expire refuses to remove backups if the oldest retained one has checksum errors. Set checksum-page-error=n only if you have decided to accept those pages.
How do their architectures differ: backup server, repository, or agent?
The main difference is which machine does the work and which way the data flows.
- Barman is a backup server that pulls. It copies base backups with
pg_basebackup(backup_method = postgres) or rsync over SSH (rsync, the default) and keeps a catalog of backups and WAL. The separatebarman-cli-cloudpackage addsbarman-cloud-*scripts that push from the database host to object storage. - pgBackRest runs on the database host and writes to one or more repositories: a local path, object storage, or a repository host connected over SSH or pgBackRest's TLS server.
- WAL-G runs on the database host and pushes to object storage. Its remote mode streams over the replication protocol, but the docs say that mode has no delta backups and no multithreaded streaming.
# /etc/barman.d/pg.conf: streaming setup from the Barman quick start
[pg]
conninfo = host=pghost user=barman dbname=postgres
streaming_conninfo = host=pghost user=streaming_barman dbname=postgres
backup_method = postgres
streaming_archiver = on
slot_name = barman
create_slot = autoInterpretation: the Barman host connects to PostgreSQL, not the other way round. With create_slot = auto, barman cron creates the replication slot and starts pg_receivewal.
pgBackRest, Barman, and WAL-G feature by feature
Switch tools to compare the same eight rows; versions as of November 2026
pgBackRest 2.60
| Feature | pgBackRest |
|---|---|
| Where it runs | Database host; optional repository host over SSH or TLS |
| Backup types | Full, differential, incremental; block incremental with repo-block |
| PostgreSQL 17 native incremental | Not used; own mechanism |
| WAL capture | archive-push, optionally asynchronous |
| Parallelism setting | process-max, default 1 |
| Encryption | repo-cipher-type=aes-256-cbc |
| Object storage | S3, Azure, GCS, SFTP |
| Verification | verify command, checksums on restore |
Barman 3.20
| Feature | Barman |
|---|---|
| Where it runs | Dedicated server that pulls; cloud scripts push from the database host |
| Backup types | Full; rsync file-level reuse; block-level incremental on PostgreSQL 17+ |
| PostgreSQL 17 native incremental | Yes, since 3.11.0 (backup_method = postgres) |
| WAL capture | barman-wal-archive or pg_receivewal streaming |
| Parallelism setting | parallel_jobs for rsync copies, default 1 |
| Encryption | encryption = gpg (tar backups and WAL) |
| Object storage | S3, Azure Blob Storage, GCS |
| Verification | check, verify-backup (pg_verifybackup) |
WAL-G v3.0.9
| Feature | WAL-G |
|---|---|
| Where it runs | Agent on the database host; optional remote mode |
| Backup types | Full and delta backups (WALG_DELTA_MAX_STEPS) |
| PostgreSQL 17 native incremental | Not used; own mechanism |
| WAL capture | wal-push, or wal-receive streaming |
| Parallelism setting | WALG_UPLOAD_CONCURRENCY, default 16 |
| Encryption | libsodium or OpenPGP keys |
| Object storage | S3, GCS, Azure, Swift, Alibaba OSS, SSH, filesystem |
| Verification | wal-verify, page checks with backup-push --verify |
Read the defaults: pgBackRest and Barman copy with one process unless you raise process-max or parallel_jobs. WAL-G uploads with 16 streams by default. Sources: each project's configuration reference.
Which tools support incremental backups, including PostgreSQL 17's?
PostgreSQL 17 added native incremental backups. pg_basebackup --incremental copies only blocks changed since a prior backup, and pg_combinebackup rebuilds a full data directory at restore time. The WAL summarizer must be running: summarize_wal defaults to off, and wal_summary_keep_time defaults to 10 days.
Barman added PostgreSQL 17 incremental support in 3.11.0 (22 August 2024). It needs backup_method = postgres and summarize_wal on before the first full backup, and it cannot mix with rsync file-level backups. 3.15.0 allowed compressed and encrypted incrementals. 3.18.0 added incrementals straight to cloud storage, marked experimental.
# postgresql.conf on PostgreSQL 17 or later, then reload:
# summarize_wal = on
# On the Barman server: a full backup, then incrementals against it
barman backup pg
barman backup --incremental latest-full pgInterpretation: latest-full picks the newest full backup as the parent. If an incremental fails because WAL summaries are missing, the gap since the parent was longer than wal_summary_keep_time, so take a new full backup.
pgBackRest has full, differential, and incremental backups, and added block incremental in 2.46 (22 May 2023), which stores only the changed parts of a file. It does not call pg_basebackup, and its user guide does not ask for summarize_wal. Enable repo1-bundle before repo1-block.
# /etc/pgbackrest/pgbackrest.conf
[global]
repo1-bundle=y
repo1-block=ysudo -u postgres pgbackrest --stanza=demo --type=full backup
sudo -u postgres pgbackrest --stanza=demo --type=diff backup
sudo -u postgres pgbackrest --stanza=demo --type=incr backupInterpretation: a differential depends only on the last full backup. An incremental depends on the previous backup of any type, so a long chain means more backups to read at restore time.
WAL-G calls its incrementals delta backups. They stay off until you set WALG_DELTA_MAX_STEPS, the number of deltas allowed between full backups. Its documentation does not describe using PostgreSQL 17 WAL summaries.
export WALG_S3_PREFIX=s3://pg-backups/prod-main
export WALG_DELTA_MAX_STEPS=6
export WALG_DELTA_ORIGIN=LATEST_FULL
wal-g backup-push "$PGDATA"Interpretation: WAL-G takes up to six deltas after each full backup, each compared with that full backup (LATEST_FULL).
How does each tool archive WAL: archive_command or streaming?
Point-in-time recovery (PITR) needs an unbroken WAL stream from a base backup up to the target time. All three tools accept WAL through PostgreSQL's archive_command. Barman and WAL-G can also stream it over a replication connection, which ships WAL as it is written instead of one segment at a time.
# postgresql.conf: pick the line for your tool
archive_mode = on
archive_command = 'pgbackrest --stanza=demo archive-push %p'
# archive_command = 'barman-wal-archive barmanhost pg %p'
# archive_command = 'wal-g wal-push %p'Interpretation: PostgreSQL retries a segment until the command exits with zero. While it fails, unarchived WAL builds up in pg_wal until the disk fills.
pgBackRest's archive-async=y hands segments to a background process that pushes several in parallel. Barman's streaming_archiver = on runs pg_receivewal with a replication slot, and WAL-G's wal-receive uses a slot named walg by default. A slot keeps WAL on the primary until the receiver has it, so a stopped receiver also fills the disk.
-- On the primary: archiver failures and slot lag
SELECT failed_count, last_failed_wal, last_failed_time FROM pg_stat_archiver;
SELECT slot_name, active,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained
FROM pg_replication_slots;Interpretation: a growing failed_count means the archive command is failing. An inactive slot with growing retained means the streaming receiver has stopped. Alert on both.
WAL archiving plus base backups, then a PITR restore
The same flow for all three tools: two streams in, one restore out
The weak link is step 1: a base backup without the WAL that follows it restores only to the moment that backup finished. A gap in the archive ends PITR at the gap.
How do parallelism, compression, and encryption compare?
No project publishes a speed comparison against the others, so measure on your own data. The docs do give the settings and defaults.
| Setting | pgBackRest | Barman | WAL-G |
|---|---|---|---|
| Parallel workers | process-max, default 1 | parallel_jobs (rsync copy), default 1 | WALG_UPLOAD_CONCURRENCY, default 16 |
| Compression | compress-type: gz (default), lz4, zst, bz2, none | backup_compression: gzip, lz4, zstd, none | WALG_COMPRESSION_METHOD: lz4 (default), lzma, zstd, brotli, none |
| Encryption | repo-cipher-type=aes-256-cbc with a passphrase | encryption = gpg plus encryption_key_id (3.14.0 and later) | WALG_LIBSODIUM_KEY or WALG_PGP_KEY |
Barman's GPG encryption needs backup_method = postgres, backup_compression_format = tar, and a compression setting (none counts), and restoring such a backup needs a staging area. Its lz4 and zstd backup compression need PostgreSQL 15 or later.
# pgbackrest.conf: parallel, zstd-compressed, encrypted repository
[global]
process-max=4
compress-type=zst
repo1-cipher-type=aes-256-cbc
repo1-cipher-pass=<long random passphrase from your secret store>Interpretation: process-max also applies to restore and asynchronous archiving, so size it against the CPU you can spare on the database host. Keep the cipher passphrase outside the repository. Without it, the backups cannot be restored.
Which object stores do they support, and how does retention work?
pgBackRest's repo-type accepts posix, cifs, s3, azure, gcs, and sftp. A stanza can use several repositories, such as a local one for fast restores and an object store for longer retention. On versioned S3, Azure, or GCS buckets it can read the repository as it was at an earlier time. Barman supports S3 and S3-compatible stores, Azure Blob Storage, and GCS. WAL-G supports S3, GCS, Azure, Swift, Alibaba OSS, SSH, and a local filesystem.
# pgBackRest: keep 14 days of full backups (count is the default type)
repo1-retention-full-type=time
repo1-retention-full=14
# Barman (server section): a recovery window, with at least 2 backups kept
retention_policy = RECOVERY WINDOW OF 14 DAYS
minimum_redundancy = 2Interpretation: pgBackRest's expire runs after each backup and removes the WAL that only expired backups needed. Barman applies its policy during barman cron.
# WAL-G: dry run first, then delete; keeps 5 full backups and their deltas
wal-g delete retain FULL 5
wal-g delete retain FULL 5 --confirmInterpretation: delete is a dry run until you add --confirm. WAL-G orders backups by the timeline in their names. After pg_upgrade the timeline can restart low, and retain may then delete new backups, so the docs add --use-sentinel-time for that case.
How do you verify backups and prove point-in-time recovery works?
Each tool can check its repository, but only a restore proves the backups work.
- pgBackRest:
checkconfirms archiving and configuration, andverifychecks that the backups and archive in a repository are valid. - Barman:
barman checktests the server setup, with--nagiosoutput for monitoring.barman verify-backuprunspg_verifybackup(PostgreSQL 13 or later). Tar or compressed backups need the PostgreSQL 18 version, and encrypted backups cannot be verified this way. - WAL-G:
wal-verify integrity timelinechecks that every WAL segment since the oldest backup is in storage.
pgbackrest info on a stanza with a full and a differential backup
Output from the pgBackRest 2.60.0 user guide (PostgreSQL 14 demo), indentation shortened
What to read: the oldest backup's timestamp is the earliest point you can restore to, and the WAL range shows what can be replayed after it. For alerts, use --output=json, which the pgBackRest user guide says stays stable across releases.
The drill below uses pgBackRest on a scratch host with the same PostgreSQL major version and a pgbackrest.conf that can read the production repository. The Barman and WAL-G restore commands follow it.
PITR restore drill with pgBackRest
Six steps on a scratch host; production keeps running throughout
-
Record a target time and a check value
On production, note the time and a value you can compare later.
psql -Atc "SELECT now(), count(*) FROM orders;" -
Confirm the repository covers the target
The target must fall after the end of a backup, inside the WAL range.
sudo -u postgres pgbackrest --stanza=demo info -
Verify the repository
Reads backup and archive files, so run it off-peak on large repositories.
sudo -u postgres pgbackrest --stanza=demo \ verify --output=text -
Restore to the target with archiving off
--archive-mode=offstops the promoted scratch cluster from pushing WAL into the production repository.sudo -u postgres pgbackrest --stanza=demo \ --delta --type=time \ "--target=2026-10-18 10:15:00+00" \ --target-action=promote \ --archive-mode=off restore -
Start PostgreSQL and compare the check value
Allow for writes between the noted time and the target.
sudo systemctl start postgresql-17 psql -Atc "SELECT count(*) FROM orders;" -
Record the elapsed time, then remove the cluster
Steps 4 and 5 give your measured restore time. Compare it with the downtime the business can accept.
sudo systemctl stop postgresql-17
Main risk: forgetting --archive-mode=off in step 4. A promoted scratch cluster that archives into the production stanza writes a new timeline into the repository you rely on.
# Barman: restore to a remote scratch host, fetching WAL on demand
barman restore pg latest /var/lib/pgsql/17/data \
--target-time "2026-10-18 10:15:00+00" \
--target-action promote \
--remote-ssh-command "ssh postgres@scratch-01" \
--get-walInterpretation: a timestamp without a time zone is read in the Barman host's zone, so always write the offset. --get-wal makes PostgreSQL fetch WAL from Barman during recovery instead of Barman copying it all first.
# WAL-G: fetch the base backup, then let PostgreSQL replay WAL to the target
wal-g backup-fetch /var/lib/pgsql/17/data LATEST
cat >> /var/lib/pgsql/17/data/postgresql.auto.conf <<'EOF'
restore_command = 'wal-g wal-fetch %f %p'
recovery_target_time = '2026-10-18 10:15:00+00'
recovery_target_action = 'promote'
archive_mode = off
EOF
touch /var/lib/pgsql/17/data/recovery.signalInterpretation: WAL-G only fetches files. PostgreSQL does the replay, so the targets are ordinary recovery settings, and recovery.signal starts targeted recovery on PostgreSQL 12 and later.
Which Kubernetes operators use which tool, and how do you monitor them?
On Kubernetes the operator usually picks the tool. CloudNativePG's backup documentation says built-in Barman Cloud support was deprecated in 1.26 in favor of the Barman Cloud Plugin. 1.31 is the last minor release with it, and it is removed from 1.32.0. The plugin needs CloudNativePG 1.26 or later. As of November 2026 the latest releases are CloudNativePG 1.30.1 and plugin 0.15.1. Crunchy Data's PGO and the Percona Operator for PostgreSQL run pgBackRest. Zalando's postgres-operator uses the Spilo image, which backs up with WAL-G.
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: s3-store
spec:
retentionPolicy: "30d"
configuration:
destinationPath: s3://backups/
s3Credentials:
accessKeyId: {name: object-store, key: ACCESS_KEY_ID}
secretAccessKey: {name: object-store, key: ACCESS_SECRET_KEY}
---
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: cluster-example
spec:
plugins:
- name: barman-cloud.cloudnative-pg.io
isWALArchiver: true
parameters:
barmanObjectName: s3-storeInterpretation: the ObjectStore holds the bucket, credentials, and retention, and the cluster references it. Clusters still on .spec.backup.barmanObjectStore must move to the plugin before upgrading to 1.32.
Outside Kubernetes, alert on the newest backup's age and on WAL gaps, not only on the backup job's exit code.
pgbackrest --stanza=demo info --output=json # stable JSON for alerting
barman check --nagios pg # Nagios-compatible status line
wal-g backup-list --detail --json # backup times and sizes
wal-g wal-verify integrity timeline # WAL gaps and timeline checksInterpretation: a WAL-G integrity status of FAILURE means at least one segment is MISSING_LOST, so PITR past that point will fail. WAL-G can also send metrics to StatsD through WALG_STATSD_ADDRESS.
Which backup tool should you choose for your scenario?
Choose by operating model first. Speed matters only once you have measured a difference on your own data.
| Scenario | Usual choice | Why |
|---|---|---|
| CloudNativePG | Barman Cloud Plugin | The supported object-store path; built-in support ends at 1.32 |
| Crunchy PGO or Percona Operator | pgBackRest | Built into both operators |
| Zalando postgres-operator | WAL-G | Shipped in the Spilo image |
| Many VMs, one central backup host | Barman, or pgBackRest with a repository host | One host holds the catalog, retention, and restore tooling |
| Large databases, tight backup windows | pgBackRest block incremental, or Barman with PostgreSQL 17 incrementals | Both copy changed blocks only; measure before deciding |
| Agents only, object storage, several engines | WAL-G | The same project also covers MySQL, MariaDB, and MongoDB (beta) |
Switching tools later is a project: repository formats are not shared, so keep the old repository until the new one covers your full retention window.
Frequently asked questions
Is pgBackRest still maintained in 2026?
Yes. Its maintainer announced on 27 April 2026 that pgBackRest was no longer maintained. On 18 May 2026 the project said it would continue, funded by AWS, Supabase, pgEdge, Tiger Data, Percona, and Eon.io. Releases resumed with 2.59.0 in July, and 2.60.0 shipped on 18 October 2026.
Does pgBackRest support PostgreSQL 17 incremental backup?
pgBackRest backs up PostgreSQL 17 but does not use its native incremental backup. It has its own full, differential, and incremental backups, plus block incremental since 2.46, enabled with repo-bundle and repo-block. Of these three tools, Barman is the one that drives pg_basebackup --incremental, from version 3.11.0, with summarize_wal enabled.
Which backup tool does CloudNativePG use?
CloudNativePG uses Barman Cloud, now through the Barman Cloud Plugin, which needs CloudNativePG 1.26 or later. Built-in barmanObjectStore support was deprecated in 1.26, 1.31 is the last minor release that has it, and it is removed from 1.32.0. Volume snapshots are the other backup option, and PITR still needs a WAL archive.
Can WAL-G do point-in-time recovery?
Yes. WAL-G fetches a base backup with backup-fetch and serves WAL through wal-fetch in PostgreSQL's restore_command. PostgreSQL then replays WAL up to recovery_target_time or another target. Run wal-g wal-verify integrity regularly, because a missing WAL segment stops point-in-time recovery at that gap.
Key takeaways
- All three tools are maintained as of November 2026; pgBackRest's April stop was reversed on 18 May by a sponsor group.
- Barman drives PostgreSQL 17 native incremental backups. pgBackRest (block incremental) and WAL-G (delta backups) use their own mechanisms.
- On Kubernetes, follow the operator, and move CloudNativePG clusters to the Barman Cloud Plugin before 1.32.
- Prove backups with a scheduled PITR drill on a scratch host, with archiving off on the restored cluster.
Plan PostgreSQL backups and restore drills with JusDB
JusDB's backup and disaster recovery team can review your pgBackRest, Barman, or WAL-G setup and check WAL archiving and retention against the data loss and downtime your business can accept (RPO and RTO). We can also plan and run a timed point-in-time restore drill with you.
Bring your PostgreSQL versions, backup configuration, storage targets, and current restore procedure (runbook). Your team approves every production change.