How to Set Up pgBackRest for PostgreSQL Backups and Point-in-Time Recovery

Updated on Aug 18, 2026
Mila H
10 MINS READ
Table of Contents
pgBackRest for PostgreSQL backups and recovery

If you've ever lost hours of database changes because your last pg_dump was too old, you already understand why pgBackRest for PostgreSQL backups and recovery exists. pgBackRest is a purpose-built backup and restore tool for PostgreSQL that handles full backups, incremental backups, WAL archiving, and point-in-time recovery, all in one package.

Unlike pg_dump, which gives you a snapshot of a single moment, pgBackRest continuously archives your Write-Ahead Log (WAL) so you can recover to any specific second. This guide teaches the entire setup.

What is pgBackRest?

pgBackRest is an open-source backup solution built specifically for PostgreSQL. At the current time, the latest stable release is pgBackRest 2.58.0, released in January 2026. It supports local repositories, remote servers, S3-compatible storage, Azure Blob, and GCS. Key features include:

  • Full, differential, and incremental backup types.
  • Continuous WAL archiving for point-in-time recovery.
  • Parallel compression using zstd, lz4, or gzip.
  • AES-256-CBC encryption for backup repositories.
  • Configurable retention policies for backups and WAL archives.
  • A check command to verify the entire pipeline is working before you need it.

Running PostgreSQL on a reliable dedicated server is important for a stable backup environment. A PerLod Dedicated Server gives you full control over disk layout, I/O throughput, and network configuration, which directly affects backup and restore speed.

How PITR (Point-in-Time Recovery) Works

Point-in-Time Recovery combines two things:

  • A base backup: a full copy of all database files at a point in time.
  • Continuous WAL archiving: every change is recorded in WAL segments, stored as they are completed.

When a disaster happens, PostgreSQL restores the base backup and then replays WAL segments one by one, stopping exactly at your chosen timestamp. This means you can recover to any second between the last base backup and the last archived WAL segment, not just to your last pg_dump snapshot.

Important Note: Recovery in PostgreSQL is greedy by default. Without specifying a target time or restore point, PostgreSQL will replay every available WAL segment and bring the database to the most recent state, including any accidental deletes. Always set --target when doing PITR.

Prerequisites to Set up pgBackRest for PostgreSQL Backups and Recovery

Before you begin to set up pgBackRest for PostgreSQL backups and recovery, make sure you have:

  • Ubuntu 22.04 or higher. You can also use Debian 11 or higher.
  • PostgreSQL 14, 15, or 16 is already installed and running.
  • A dedicated partition or directory for the backup repository, separate from the data directory.
  • sudo access on the server.

Once you are done, you can proceed to the following steps to set up pgBackRest for PostgreSQL backups and recovery.

Step 1: Install pgBackRest

On Ubuntu and Debian, pgBackRest is available directly from the apt repositories. Run the system update and install pgBackRest:

Bash
sudo apt updatesudo apt install pgbackrest -y

Verify the installation:

Bash
pgbackrest version

Step 2: Create Required Directories

pgBackRest needs a repository directory to store backups and WAL archives and a log directory. For this purpose, run the commands below:

Bash
# Backup repositorysudo mkdir -p /var/lib/pgbackrestsudo chmod 750 /var/lib/pgbackrestsudo chown postgres:postgres /var/lib/pgbackrest # Log directorysudo mkdir -p /var/log/pgbackrestsudo chmod 770 /var/log/pgbackrestsudo chown postgres:postgres /var/log/pgbackrest # Config directorysudo mkdir -p /etc/pgbackrest/conf.dsudo touch /etc/pgbackrest/pgbackrest.confsudo chmod 640 /etc/pgbackrest/pgbackrest.confsudo chown postgres:postgres /etc/pgbackrest/pgbackrest.conf

Step 3: Configure pgBackRest

Now you must edit the pgBackRest config file. Open the config file:

Bash
sudo nano /etc/pgbackrest/pgbackrest.conf

Add the following configuration. Replace main with your stanza name, which is a logical name for your PostgreSQL cluster, and adjust pg1-path to match your actual data directory:

Bash
[main]pg1-path=/var/lib/postgresql/16/main [global]repo1-path=/var/lib/pgbackrestrepo1-retention-full=2repo1-retention-diff=7repo1-cipher-type=aes-256-cbcrepo1-cipher-pass=YourStrongPassphraseHere process-max=4compress-type=zstcompress-level=6 log-level-console=infolog-level-file=detaillog-path=/var/log/pgbackrest

What each option does:

Option Purpose
pg1-path Path to PostgreSQL data directory
repo1-path Where backups and WAL archives are stored
repo1-retention-full=2 Keep the last 2 full backups
repo1-retention-diff=7 Keep the last 7 differential backups
repo1-cipher-type=aes-256-cbc Encrypt repository with AES-256
process-max=4 Parallel processes for faster backup/restore
compress-type=zst Use zstd compression (faster than gzip)

Step 4: Configure PostgreSQL for WAL Archiving

At this point, you must edit your PostgreSQL configuration file. For example, on Ubuntu 22.04 with PostgreSQL 16, this is at /etc/postgresql/16/main/postgresql.conf:

Bash
sudo nano /etc/postgresql/16/main/postgresql.conf

Add or modify these lines:

Bash
wal_level = replicaarchive_mode = onarchive_command = 'pgbackrest --stanza=main archive-push %p'archive_timeout = 60max_wal_senders = 3

Restart PostgreSQL to apply the changes:

Bash
sudo systemctl restart postgresql

Step 5: Create the Stanza

A stanza is just the pgBackRest term for a named configuration group connected to one PostgreSQL cluster. You can create it with:

Bash
sudo -u postgres pgbackrest --stanza=main stanza-create

In your output, you should see:

HTML/XML
stanza-create command end: completed successfully

Step 6: Verify the WAL Archiving Configuration

You can easily run the check command to verify that WAL archiving is working correctly:

Bash
sudo -u postgres pgbackrest --stanza=main --log-level-console=info check

A successful output looks like this:

HTML/XML
P00 INFO: check repo1 configuration (primary)P00 INFO: check repo1 archive for WAL (primary)P00 INFO: WAL segment 000000010000000000000001 successfully archivedP00 INFO: check command end: completed successfully

If you see errors here, do not proceed. Fix the issue first.

You can also verify your WAL archiving status from inside PostgreSQL:

SQL
SELECT name, settingFROM pg_settingsWHERE name IN ('archive_mode', 'archive_command', 'archive_timeout', 'wal_level');

And check for archiving failures:

SQL
SELECT  archived_count,  failed_count,  last_archived_wal,  last_archived_time,  now() - last_archived_time AS archive_lagFROM pg_stat_archiver;

A non-zero failed_count means WAL segments are piling up on disk. Troubleshoot immediately.

Step 7: Take Your First Full Backup with pgBackRest

Use the command below to run your first full backup:

Bash
sudo -u postgres pgbackrest --stanza=main --type=full --log-level-console=info backup

Output will show something like:

HTML/XML
P00 INFO: backup command begin 2.58.0P00 INFO: execute backup startP00 INFO: full backup size = 25MB, file total = 963P00 INFO: backup command end: completed successfully

Check what's in the repository:

Bash
sudo -u postgres pgbackrest info

This shows you the backup catalog, including label, start and stop timestamps, backup size, and WAL range.

Tips: If you're working with PostgreSQL extensions like pgvector for AI workloads, you can check out this guide on installing pgvector on PostgreSQL. Proper backup coverage is equally important for vector-enabled databases.

Step 8: Run pgBackRest Differential and Incremental Backups

Understanding backup types is key to building a solid strategy:

Type What It Backs Up When to Use
Full All database files Weekly
Differential Changes since last full backup Daily
Incremental Changes since the last backup of any type Every 6 hours

Run a differential backup with:

Bash
sudo -u postgres pgbackrest --stanza=main --type=diff --log-level-console=info backup

Run an incremental backup with:

Bash
sudo -u postgres pgbackrest --stanza=main --type=incr --log-level-console=info backup

Notice the size difference; a differential or incremental backup is much smaller than a full backup because it only stores changed blocks.

Step 9: Set Up a pgBackRest Backup Schedule with Cron

You can easily automate backups with cron. Open the crontab:

Bash
sudo crontab -u postgres -e

Add these lines:

Bash
# Full backup every Sunday at 2:00 AM0 2 * * 0 pgbackrest --stanza=main --type=full backup # Differential backup Monday–Saturday at 2:00 AM0 2 * * 1-6 pgbackrest --stanza=main --type=diff backup # Incremental backup every 6 hours0 */6 * * * pgbackrest --stanza=main --type=incr backup

This gives you weekly full backups, daily differentials, and 6-hourly incrementals.

Step 10: Understanding Retention Policy in pgBackRest

The retention settings you put in pgbackrest.conf control how long backups are kept:

Bash
repo1-retention-full=2          # Keep last 2 full backupsrepo1-retention-diff=7          # Keep last 7 differential backups

When a full backup expires, all differential and incremental backups that depended on it are automatically removed. WAL archives older than the oldest retained full backup are also cleaned up automatically.

To retain backups by time instead of count, you can use:

Bash
repo1-retention-full-type=timerepo1-retention-full=30         # Keep all full backups from last 30 days

Warning: Do not expire WAL archives independently of backups. If you remove WAL segments that sit between two retained backups, PITR into that gap becomes impossible.

Step 11: Live PITR Test | Validate Your Recovery Plan

At this point, by running a full recovery (PITR) scenario, you can validate your plan.

First, create test data with:

SQL
-- Connect to PostgreSQLsudo -u postgres psql -- Create a test tableCREATE TABLE important_orders (  id serial PRIMARY KEY,  customer text,  amount numeric); INSERT INTO important_orders (customer, amount)VALUES ('Alice', 500.00), ('Bob', 750.00), ('Charlie', 1200.00); -- Record the current timestamp BEFORE the "accident"SELECT current_timestamp;-- Example output: 2026-06-11 10:15:30.123456+00

Then, take an Incremental Backup:

Bash
sudo -u postgres pgbackrest --stanza=main --type=incr backup

Then, simulate data loss:

SQL
-- "Accidental" table dropDROP TABLE important_orders; -- Confirm it's goneSELECT * FROM important_orders;-- ERROR: relation "important_orders" does not exist

To recover to the moment before the drop, stop PostgreSQL first:

Bash
sudo systemctl stop PostgreSQL

Clear the data directory and restore to the timestamp just before the DROP:

Bash
sudo -u postgres find /var/lib/postgresql/16/main -mindepth 1 -delete sudo -u postgres pgbackrest --stanza=main \  --type=time \  "--target=2026-06-11 10:15:30.123456+00" \  --target-action=promote \  --delta \  restore

What --target-action=promote does: After replaying WAL up to the target time, PostgreSQL promotes the recovered cluster to a normal read-write database. Without this flag, the database stays in read-only recovery mode.

Start PostgreSQL and verify the data is back:

Bash
sudo systemctl start PostgreSQLsudo -u postgres psql -c "SELECT * FROM important_orders;"

Expected output:

HTML/XML
 id | customer | amount----+----------+---------  1 | Alice    | 500.00  2 | Bob      | 750.00  3 | Charlie  | 1200.00(3 rows)

The table is restored exactly as it was at 10:15:30, before the DROP.

Step 12: Create Restore Points Before Migrations

For planned risky operations like schema migrations and bulk deletes, you can create a named restore point:

SQL
-- Before the risky migrationSELECT pg_create_restore_point('before_june_migration');

If something goes wrong, restore to that exact point by name:

Bash
sudo systemctl stop postgresql sudo -u postgres pgbackrest --stanza=main \  --type=name \  --target="before_june_migration" \  --target-action=promote \  restore sudo systemctl start postgresql

Named restore points are more reliable than timestamps; a timestamp has rounding effects at the microsecond level.

Pick the Right Backup Repository Location

Where you store your backup repository matters. Here are the storage options for pgBackRest repositories:

Location Pros Cons
Local filesystem Fast, simple setup Lost if the server fails
Separate server (SSH) Off-host, survives server failure Needs SSH key setup
S3 / S3-compatible Durable, off-site, scalable Slightly slower, costs money
Azure Blob / GCS Same benefits as S3 Vendor-specific setup

For production, always store backups off the database server. The same disk failure destroys a backup on the same disk. An affordable Linux VPS makes an excellent dedicated backup repository host, is cost-effective, isolated from your main database server, and easy to access via SSH.

How to Monitor pgBackRest Backups

Never assume backups are working; always check them. View the current backup catalog:

Bash
sudo -u postgres pgbackrest info

Check for WAL archiving issues from inside PostgreSQL:

SQL
SELECT  archived_count,  failed_count,  last_archived_wal,  last_archived_time,  now() - last_archived_time AS archive_lagFROM pg_stat_archiver;

Alert on these three metrics:

  • Archive lag > 5 minutes: pipeline may be broken.
  • failed_count > 0: WAL archiving is failing.
  • Backup age > your backup interval with buffer: scheduler may have failed.

For deeper PostgreSQL health, the PostgreSQL autovacuum tuning guide covers how to keep your database in optimal condition, which directly improves recovery speed.

Test pgBackRest Recovery Regularly

A backup that has never been tested is not a backup. Run a monthly recovery test on a separate path:

Bash
sudo -u postgres pgbackrest --stanza=main \  --type=time \  "--target=2026-06-01 02:00:00+00" \  --target-action=promote \  --pg1-path=/var/lib/postgresql/16/test_recovery \  restore

After restoring, start a temporary PostgreSQL instance that points to that path and verify that the data looks correct. Record the recovery time; that is your real RTO.

Conclusion

Setting up pgBackRest for PostgreSQL backups and recovery is one of the best choices you can make for any production database. By combining base backups with continuous WAL archiving, pgBackRest gives you the ability to recover to any second in time. Just remember to test your recovery process before you actually need it.

We hope you enjoy this guide. For more information, you can visit the pgBackRest Official User Guide.

WAL segments accumulate on the primary server and can fill the disk. Monitor pg_stat_archiver.failed_count to catch this early.

No. pgBackRest takes backups online without stopping PostgreSQL or locking tables.

A stanza is a named configuration section that represents one PostgreSQL cluster. You can have multiple stanzas for multiple clusters in the same config file.