JusDB
Free DB Audit
PostgreSQL

Barman vs pgBackRest vs WAL-G for PostgreSQL Backup

Compare Barman, pgBackRest, and WAL-G as of November 2026: maintenance status, PostgreSQL 17 incremental support, WAL archiving, retention, Kubernetes operators, and a PITR drill.

JusDB Team
Published October 19, 2026
Updated November 9, 2026
17 min read

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.

TL;DR
  • 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).

bash
# Record the installed version on every database and backup host
pgbackrest version
barman --version
wal-g --version

Interpretation: 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.

Two behavior changes in recent pgBackRest releases

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 separate barman-cli-cloud package adds barman-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.
ini
# /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 = auto

Interpretation: 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

FeaturepgBackRest
Where it runsDatabase host; optional repository host over SSH or TLS
Backup typesFull, differential, incremental; block incremental with repo-block
PostgreSQL 17 native incrementalNot used; own mechanism
WAL capturearchive-push, optionally asynchronous
Parallelism settingprocess-max, default 1
Encryptionrepo-cipher-type=aes-256-cbc
Object storageS3, Azure, GCS, SFTP
Verificationverify command, checksums on restore

Barman 3.20

FeatureBarman
Where it runsDedicated server that pulls; cloud scripts push from the database host
Backup typesFull; rsync file-level reuse; block-level incremental on PostgreSQL 17+
PostgreSQL 17 native incrementalYes, since 3.11.0 (backup_method = postgres)
WAL capturebarman-wal-archive or pg_receivewal streaming
Parallelism settingparallel_jobs for rsync copies, default 1
Encryptionencryption = gpg (tar backups and WAL)
Object storageS3, Azure Blob Storage, GCS
Verificationcheck, verify-backup (pg_verifybackup)

WAL-G v3.0.9

FeatureWAL-G
Where it runsAgent on the database host; optional remote mode
Backup typesFull and delta backups (WALG_DELTA_MAX_STEPS)
PostgreSQL 17 native incrementalNot used; own mechanism
WAL capturewal-push, or wal-receive streaming
Parallelism settingWALG_UPLOAD_CONCURRENCY, default 16
Encryptionlibsodium or OpenPGP keys
Object storageS3, GCS, Azure, Swift, Alibaba OSS, SSH, filesystem
Verificationwal-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.

bash
# 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 pg

Interpretation: 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.

ini
# /etc/pgbackrest/pgbackrest.conf
[global]
repo1-bundle=y
repo1-block=y
bash
sudo -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 backup

Interpretation: 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.

bash
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.

ini
# 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.

sql
-- 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

WAL archiving and base backups feeding a point-in-time restore Step 1: the PostgreSQL primary sends WAL segments to the backup repository through archive_command or streaming replication. Step 2: the backup tool copies base backups, full and then differential or incremental, into the same repository. Step 3: a restore copies one base backup to a scratch host or new primary and replays archived WAL up to the target time. PostgreSQL primary Backup repository server, host or bucket Restored cluster scratch or new primary 1 2 3 1: WAL segments through archive_command or streaming replication 2: base backups, a full backup and then differentials or incrementals 3: restore one base backup, then replay WAL to the target time

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.

SettingpgBackRestBarmanWAL-G
Parallel workersprocess-max, default 1parallel_jobs (rsync copy), default 1WALG_UPLOAD_CONCURRENCY, default 16
Compressioncompress-type: gz (default), lz4, zst, bz2, nonebackup_compression: gzip, lz4, zstd, noneWALG_COMPRESSION_METHOD: lz4 (default), lzma, zstd, brotli, none
Encryptionrepo-cipher-type=aes-256-cbc with a passphraseencryption = 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.

ini
# 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.

ini
# 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 = 2

Interpretation: pgBackRest's expire runs after each backup and removes the WAL that only expired backups needed. Barman applies its policy during barman cron.

bash
# 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 --confirm

Interpretation: 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: check confirms archiving and configuration, and verify checks that the backups and archive in a repository are valid.
  • Barman: barman check tests the server setup, with --nagios output for monitoring. barman verify-backup runs pg_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 timeline checks 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

postgres@pg-primary:~
$ sudo -u postgres pgbackrest infostanza: demo status: ok cipher: aes-256-cbc db (current) wal archive min/max (14): 000000010000000000000001/000000010000000000000005 full backup: 20261015-070108F timestamp start/stop: 2026-10-15 07:01:08+00 / 2026-10-15 07:01:10+00 wal start/stop: 000000010000000000000002 / 000000010000000000000003 database size: 25.2MB, database backup size: 25.2MB repo1: backup set size: 3.2MB, backup size: 3.2MB diff backup: 20261015-070108F_20261015-070110D database size: 25.2MB, database backup size: 9.2KB repo1: backup set size: 3.2MB, backup size: 864B backup reference total: 1 full

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

  1. 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;"
  2. 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
  3. 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
  4. Restore to the target with archiving off

    --archive-mode=off stops 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
  5. 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;"
  6. 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.

bash
# 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-wal

Interpretation: 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.

bash
# 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.signal

Interpretation: 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.

yaml
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-store

Interpretation: 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.

bash
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 checks

Interpretation: 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.

ScenarioUsual choiceWhy
CloudNativePGBarman Cloud PluginThe supported object-store path; built-in support ends at 1.32
Crunchy PGO or Percona OperatorpgBackRestBuilt into both operators
Zalando postgres-operatorWAL-GShipped in the Spilo image
Many VMs, one central backup hostBarman, or pgBackRest with a repository hostOne host holds the catalog, retention, and restore tooling
Large databases, tight backup windowspgBackRest block incremental, or Barman with PostgreSQL 17 incrementalsBoth copy changed blocks only; measure before deciding
Agents only, object storage, several enginesWAL-GThe 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.

Share this article

Database engineering notes

Articles like this one, in your inbox. No spam, unsubscribe anytime.

JusDB Team

Official JusDB content team

Keep reading

REPACK CONCURRENTLY in PostgreSQL 19 vs pg_repack: Online Table Rebuilds

Learn what PostgreSQL 19's REPACK (CONCURRENTLY) locks, what it needs before it runs, how it compares with pg_repack, and when to keep the extension.

PostgreSQL19 minNov 9, 2026
Read

CloudNativePG: Running PostgreSQL on Kubernetes in Production

Run PostgreSQL on Kubernetes with CloudNativePG 1.30: a production Cluster manifest, synchronous replication, failover, Barman Cloud Plugin backups, PITR, PgBouncer, and upgrades.

PostgreSQL18 minNov 3, 2026
Read

PostgreSQL Advisory Locks: Patterns and Pitfalls

Use PostgreSQL advisory locks safely: session vs transaction locks, key choice, singleton jobs, leader election, and the PgBouncer, LIMIT, and lock-table traps.

PostgreSQL18 minOct 27, 2026
Read