//------------------------------------------------------------------- //-------------------------------------------------------------------
pgBackRest for PostgreSQL backups and recovery

How to Set Up pgBackRest for PostgreSQL Backups and Point-in-Time 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:

sudo apt update
sudo apt install pgbackrest -y

Verify the installation:

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:

# Backup repository
sudo mkdir -p /var/lib/pgbackrest
sudo chmod 750 /var/lib/pgbackrest
sudo chown postgres:postgres /var/lib/pgbackrest

# Log directory
sudo mkdir -p /var/log/pgbackrest
sudo chmod 770 /var/log/pgbackrest
sudo chown postgres:postgres /var/log/pgbackrest

# Config directory
sudo mkdir -p /etc/pgbackrest/conf.d
sudo touch /etc/pgbackrest/pgbackrest.conf
sudo chmod 640 /etc/pgbackrest/pgbackrest.conf
sudo chown postgres:postgres /etc/pgbackrest/pgbackrest.conf

Step 3: Configure pgBackRest

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

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:

[main]
pg1-path=/var/lib/postgresql/16/main

[global]
repo1-path=/var/lib/pgbackrest
repo1-retention-full=2
repo1-retention-diff=7
repo1-cipher-type=aes-256-cbc
repo1-cipher-pass=YourStrongPassphraseHere

process-max=4
compress-type=zst
compress-level=6

log-level-console=info
log-level-file=detail
log-path=/var/log/pgbackrest

What each option does:

OptionPurpose
pg1-pathPath to PostgreSQL data directory
repo1-pathWhere backups and WAL archives are stored
repo1-retention-full=2Keep the last 2 full backups
repo1-retention-diff=7Keep the last 7 differential backups
repo1-cipher-type=aes-256-cbcEncrypt repository with AES-256
process-max=4Parallel processes for faster backup/restore
compress-type=zstUse 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:

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

Add or modify these lines:

wal_level = replica
archive_mode = on
archive_command = 'pgbackrest --stanza=main archive-push %p'
archive_timeout = 60
max_wal_senders = 3

Restart PostgreSQL to apply the changes:

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:

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

In your output, you should see:

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:

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

A successful output looks like this:

P00 INFO: check repo1 configuration (primary)
P00 INFO: check repo1 archive for WAL (primary)
P00 INFO: WAL segment 000000010000000000000001 successfully archived
P00 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:

SELECT name, setting
FROM pg_settings
WHERE name IN ('archive_mode', 'archive_command', 'archive_timeout', 'wal_level');

And check for archiving failures:

SELECT
  archived_count,
  failed_count,
  last_archived_wal,
  last_archived_time,
  now() - last_archived_time AS archive_lag
FROM 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:

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

Output will show something like:

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

Check what’s in the repository:

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:

TypeWhat It Backs UpWhen to Use
FullAll database filesWeekly
DifferentialChanges since last full backupDaily
IncrementalChanges since the last backup of any typeEvery 6 hours

Run a differential backup with:

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

Run an incremental backup with:

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:

sudo crontab -u postgres -e

Add these lines:

# Full backup every Sunday at 2:00 AM
0 2 * * 0 pgbackrest --stanza=main --type=full backup

# Differential backup Monday–Saturday at 2:00 AM
0 2 * * 1-6 pgbackrest --stanza=main --type=diff backup

# Incremental backup every 6 hours
0 */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:

repo1-retention-full=2          # Keep last 2 full backups
repo1-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:

repo1-retention-full-type=time
repo1-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:

-- Connect to PostgreSQL
sudo -u postgres psql

-- Create a test table
CREATE 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:

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

Then, simulate data loss:

-- "Accidental" table drop
DROP TABLE important_orders;

-- Confirm it's gone
SELECT * FROM important_orders;
-- ERROR: relation "important_orders" does not exist

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

sudo systemctl stop PostgreSQL

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

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:

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

Expected output:

 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:

-- Before the risky migration
SELECT pg_create_restore_point('before_june_migration');

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

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:

LocationProsCons
Local filesystemFast, simple setupLost if the server fails
Separate server (SSH)Off-host, survives server failureNeeds SSH key setup
S3 / S3-compatibleDurable, off-site, scalableSlightly slower, costs money
Azure Blob / GCSSame benefits as S3Vendor-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:

sudo -u postgres pgbackrest info

Check for WAL archiving issues from inside PostgreSQL:

SELECT
  archived_count,
  failed_count,
  last_archived_wal,
  last_archived_time,
  now() - last_archived_time AS archive_lag
FROM 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:

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.

FAQs

What happens if WAL archiving fails?

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

Do I need to stop PostgreSQL to take a backup?

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

What is a stanza in pgBackRest?

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.

Post Your Comment

PerLod delivers high-performance hosting with real-time support and unmatched reliability.

Contact us

Payment methods

payment gateway