Follow this guide in order the first time. Each section depends on earlier sections. For example, Restore requires the configuration from Quick Start. After pgBackRest is running, you can use sections independently.
These examples use Debian/Ubuntu and PostgreSQL 17. You can adapt them to other Unix distributions and PostgreSQL versions. Only commands to create, start, stop, and drop clusters depend on the OS. pgBackRest commands are the same across Unix systems, although the executable location can differ. PostgreSQL versions can differ in paths, file names, and settings; some examples show these differences.
Configuration information and documentation for PostgreSQL can be found in the PostgreSQL Manual.
The documentation build runs each command on a virtual machine from the XML source. This verifies that commands work in the specified order. Relevant output appears below each command. Other output is omitted to keep the instructions clear.
Run commands as an unprivileged user with sudo access to root and postgres. Alternatively, run each command directly as its specified user and remove sudo.
Concepts
The following definitions apply to pgBackRest, PostgreSQL, and this guide.
Backup
A backup is a consistent copy of a database cluster. Restore it to recover from hardware failure, perform Point-In-Time Recovery, or create a standby.
Full Backup: Copy all database cluster contents. The first cluster backup is always full. pgBackRest can restore it directly without files from another backup to achieve consistency.
Differential Backup: Copy files changed since the last full backup. Restore combines those files with unchanged files from that full backup. This uses less disk space than a full backup. Both the differential and its full backup must be valid for a restore.
Incremental Backup: Copy files changed since the last backup, whether full, differential, or incremental. Incremental backups are usually much smaller than full or differential backups. A restore requires valid versions of every backup in its dependency chain. This includes all incrementals back to the preceding differential, that differential, and its full backup. If no differential exists, it includes all incrementals back to the full backup and that full backup itself.
Restore
A restore copies backup files to a system where PostgreSQL can start them as a live cluster. It requires backup files and one or more WAL segments.
Write Ahead Log (WAL)
PostgreSQL uses WAL to prevent loss of committed changes. It writes transactions sequentially to WAL and considers them committed when those writes reach disk. A background process then writes the changes to the main database files, also called the heap. After a crash, WAL replay restores database consistency.
WAL is conceptually infinite but consists of individual 16MB segment files. A segment name has the form 0000000100000A1E000000FE. The first 8 hexadecimal digits identify the timeline. The next 16 identify the logical sequence number (LSN).
Encryption
Encryption converts data into a form that requires the correct password, also called a passphrase, to read.
pgBackRest encrypts the repository with a user-supplied password to prevent unauthorized access to its stored data.
Upgrading pgBackRest
Upgrading pgBackRest from v2.x to v2.y
To upgrade from v2.x to v2.y, most installations only need the new binaries. The repository format is unchanged. You can also downgrade unless you have used features that the older version does not support.
IMPORTANT:
Local and remote pgBackRest versions must match exactly. Upgrade them together. If versions differ, WAL archiving and backups fail until they match. The error is: [ProtocolError] expected value '2.x' for greeting key 'version' but got '2.y'.
Build
Prefer package installation to a source build. See Installation for package information.
Build from source on a separate build host. Production hosts generally should not have the required build tools. pgBackRest is one executable, which you can copy to other hosts after the build.
build ⇒ Download version 2.59.2 of pgBackRest to /build path
build ⇒ Optionally run smoke tests to verify pgBackRest was built correctly
meson test -C /build/pgbackrest --suite smoke
ninja: Entering directory `/build/pgbackrest'
ninja: no work to do.
1/1 smoke OK 10.91s
[filtered 7 lines of output]
Installation
Create a host named pg-primary for the demo cluster and pgBackRest examples.
Prefer package installation to a source build. Packages usually perform the remaining steps in this section. If a package omits a directory or sets incorrect permissions, create the directory or correct its permissions manually.
Debian/Ubuntu packages for pgBackRest are available at apt.postgresql.org.
If your distribution or version has no package, build from source and follow these manual installation steps.
Check the installation. Running pgBackRest on the command line reports an error if a dependency is missing.
pg-primary ⇒ Make sure the installation worked
sudo -u postgres pgbackrest
pgBackRest 2.59.2 - General help
Usage:
pgbackrest [options] [command]
Commands:
annotate add or modify backup annotation
archive-get get a WAL segment from the archive
archive-push push a WAL segment to the archive
backup backup a database cluster
check check the configuration
expire expire backups that exceed retention
help get help
info retrieve information about backups
repo-get get a file from a repository
repo-ls list files in a repository
restore restore a database cluster
server pgBackRest server
server-ping ping pgBackRest server
stanza-create create the required stanza data
stanza-delete delete a stanza
stanza-upgrade upgrade a stanza
start allow pgBackRest processes to run
stop stop pgBackRest processes from running
verify verify contents of a repository
version get version
Use 'pgbackrest help [command]' for more information.
Quick Start
Quick Start covers basic pgBackRest and PostgreSQL configuration. It introduces backup, restore, and info.
Setup Demo Cluster
The demo cluster is optional but strongly recommended, especially for new users. Examples use this cluster on the default port, 5432. Start it in a later section after configuration is complete.
Configuring already existing cluster (configuration: /etc/postgresql/17/demo, data: /var/lib/postgresql/17/demo, owner: 102:103)
Ver Cluster Port Status Owner Data directory Log file
17 demo 5432 down postgres /var/lib/postgresql/17/demo /var/log/postgresql/postgresql-17-demo.log
Configure Cluster Stanza
A stanza contains the configuration for a PostgreSQL database cluster. It defines the cluster location, backup method, archive options, and other settings. Most database servers have one PostgreSQL cluster and one stanza. A backup server has a stanza for each cluster that needs a backup.
Choose a stanza name that describes the databases in the cluster. The primary and all replicas use the same stanza name. A functional name, such as app or dw, is preferable to a local cluster name, such as main or prod.
Use demo as the stanza name because it describes the cluster purpose.
pgBackRest needs the PostgreSQL base data directory. PostgreSQL can report it, but is unavailable during recovery. Set pg-path to exactly the data_directory value reported by PostgreSQL. Each backup compares these paths and fails if they differ.
Debian/Ubuntu stores clusters in /var/lib/postgresql/[version]/[cluster] by default. Use this location to identify the data directory.
When you create /etc/pgbackrest/pgbackrest.conf, grant read access to the database owner, usually postgres.
pg-primary:/etc/pgbackrest/pgbackrest.conf⇒ Configure the PostgreSQL cluster data directory
[demo]pg1-path=/var/lib/postgresql/17/demo
pgBackRest configuration files use a Windows INI-like format. Bracketed section names contain key/value pairs. Lines starting with # are comments; comments after a value on the same line are unsupported. Quoting is unsupported. pgBackRest trims whitespace from keys and values. Repeated sections are merged.
Configuration loading depends on these options:
Default config and config-include-path: load the default file if present. Append *.conf files from the default include path if present.
Explicit config: load only the specified file, which must exist.
Explicit config-include-path: load its *.conf files; the path must exist. Also load the default configuration file if present. Add --no-config to load only include-path files.
Explicit config and config-include-path: load the specified file and append *.conf files from the specified include path. The files must exist.
Explicit config-path: override the base path for the default configuration file and include path. Explicit config or config-include-path settings take precedence.
pgBackRest combines the files as one file, but each file must be valid independently. Each file must declare sections for its key/value pairs. File order does not determine precedence; sections do. The order from highest to lowest precedence is:
[stanza:command]
[stanza]
[global:command]
[global]
NOTE:
--config, --config-include-path and --config-path are command-line only options.
Environment variables can also configure pgBackRest, as shown below. They apply to commands such as backup, restore, and archive-push.
pg-primary ⇒ Configure log-path using the environment
pgBackRest 2.59.2 - 'backup' command - 'log-path' option help
Path where log files are stored.
The log path provides a location for pgBackRest to store log files. Note that
if log-level-file=off then no log path is required.
current: /path/set/by/env
default: /var/log/pgbackrest
Create the Repository
The repository is where pgBackRest stores backups and archives WAL segments.
To estimate repository space, take some backups. Record the sizes of full, incremental, and differential backups (full/incr/diff). Measure how much WAL the database generates each day. These measurements give an approximate space requirement. Requirements will probably change as the database changes.
This example stores the repository on the PostgreSQL host. This is the simplest configuration. It is useful when conventional backup software also backs up that host.
Enable WAL archiving before backing up a running PostgreSQL cluster. PostgreSQL uses %p to specify the WAL segment location. A backup creates at least one WAL segment, even without explicit cluster writes.
After these changes, restart the PostgreSQL cluster before taking a backup.
pg-primary ⇒ Restart the demo cluster
sudo pg_ctlcluster 17 demo restart
Keep hot_standby enabled, which is the default, on every cluster. Any cluster might later become a standby, including a former primary after failover. A standby requires this setting to accept read-only connections.
If a WAL segment needs more than the default 60 seconds to reach the repository, increase pgBackRest archive-timeout. This differs from PostgreSQL archive_timeout, which forces a WAL segment switch during long inactive periods. See PostgreSQL Write Ahead Log for archive_timeout details.
Set command-specific options for archive-push. For example, a lower compression level can speed archiving without changing backup compression.
pg-primary:/etc/pgbackrest/pgbackrest.conf⇒ Config archive-push to use a lower compression level
Set a repository cipher type and key to demonstrate encryption. Encryption always occurs on the client, even when storage such as S3 supports encryption.
Use a long, random passphrase for the cipher key. Generate one with openssl rand -base64 48.
The example puts encryption settings in [global] so info can read all stanzas. Without stanza, info reads encryption settings only from [global]. For stanza-specific encryption, supply stanza to read the encrypted stanza.
After configuring the repository and creating and checking the stanza, you cannot change its encryption settings.
Create the Stanza
Run stanza-create to initialize the stanza. Then run check to verify archive and backup configuration.
pg-primary ⇒ Create the stanza and check the configuration
P00 INFO: stanza-create command begin 2.59.2: --exec-id=418-ea48493a --log-level-console=info --no-log-timestamp --pg1-path=/var/lib/postgresql/17/demo --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=/var/lib/pgbackrest --stanza=demo
P00 INFO: stanza-create for stanza 'demo' on repo1
P00 INFO: stanza-create command end: completed successfully
Check the Configuration
The check command validates pgBackRest and archive_command configuration for the specified stanza. It checks backup and archive settings for all repositories and databases configured on the current host. It detects configuration errors, especially archive errors that leave backups incomplete because required WAL segments never reached the archive. Run it on the PostgreSQL or repository host. You can also run it on a standby, but then it checks only repository configuration. A standby cannot execute pg_switch_xlog()/pg_switch_wal().
The command calls pg_create_restore_point('pgBackRest Archive Check') and pg_switch_xlog()/pg_switch_wal() to force PostgreSQL to archive a WAL segment.
Some performance options are disabled by default to preserve repository compatibility. Enable the following options for new repositories. You can also enable them for existing repositories, but older pgBackRest versions might then be unable to read them. Compatibility depends on the feature introduction version shown below.
compress-type selects compression for backup and archive-push. The default is gz (Gzip). Prefer zst (Zstandard) for much faster processing with similar compression. Support started in v2.27. See Compress Type.
repo-bundle combines small files to save space and speed backup and restore, especially on object stores such as S3. It was introduced in v2.39. See File Bundling.
repo-block stores changed parts of files during diff/incrbackup, which saves space and speeds backups. It was introduced in v2.46, but use at least v2.52.1. See Block Incremental.
Other performance options need additional configuration, or use safe defaults that are not optimal. These options are available in every v2 release.
process-max controls the number of processes. Its default, 1, is rarely suitable. Each command uses it differently; see the command documentation.
archive-async archives WAL in batches for much higher speed. It is disabled by default because it requires a spool path. See Asynchronous Archiving.
backup-standby reduces primary load by backing up from a standby. It is disabled by default because it needs extra configuration and at least one standby. See Backup from a Standby.
Perform a Backup
By default, backups wait for the next regular checkpoint. PostgreSQL checkpoint_timeout and checkpoint_segments settings can make this a long wait. Usually, set start-fast=y to force a checkpoint and start immediately. For a daily backup, one extra checkpoint should have little performance impact. On very busy clusters, use --start-fast on the command line only when needed.
pg-primary:/etc/pgbackrest/pgbackrest.conf⇒ Configure backup fast start
No warning appeared because a full backup already existed. Incrementals can depend on a full or differential backup. Differentials must depend on a full backup. To create a full backup, run backup with --type=full.
During an online backup, pgBackRest waits for the archive to receive all WAL segments necessary for consistency. The archive-timeout default is 60 seconds. Increase it if an individual segment takes longer to archive.
Schedule a Backup
Backups can be scheduled with utilities such as cron.
The example schedules full backups at 6:30 AM each Sunday. It schedules differential backups at 6:30 AM Monday through Saturday. If installed midweek, the first differential job creates a full backup. The next day, it creates a differential.
The info command reports on one stanza or all stanzas. By default, text output summarizes backups for the requested stanzas. The text format can change in any release.
For machine-readable output, use --output=json. JSON includes much more information than text output. Its format stays stable unless a bug requires a change.
Use --detail-level=progress to show only progress and reduce execution time. This skips all checks except stanza availability.
Each stanza has a separate section. Use --stanza to show only one. The status field indicates stanza health: ok means pgBackRest operates normally. With multiple repositories, mixed means at least one repository has an unhealthy stanza; output then gives the status per repository. An unknown repository error uses the code other and includes full error details.
The wal archive min/max field shows the minimum and maximum archived WAL. With multiple repositories, it covers all repositories unless you set --repo. Archive retention policies or other causes can leave gaps in this range.
The backup/expire running and/or restore running messages appear beside status when those commands run on the host. Text output also shows progress per repository. JSON output includes a repo array.
Backups appear from oldest to newest. The oldest is always a full backup, with an F at the end of its label. The newest can be full, differential (label ends with D), or incremental (label ends with I).
The timestamp start/stop field shows when the backup ran. Use timestamp stop to select a backup for Point-In-Time Recovery. See Point-In-Time Recovery.
The wal start/stop field shows the WAL range necessary for database consistency after a restore. The backup command checks that the archive contains this range before it completes.
The database size field shows the full, uncompressed database size. The database backup size field shows the database data actually backed up. These values match for full backups.
The repo field identifies the repository that contains the backup. The backup set size includes files in this backup and referenced backups needed for a restore. The backup size includes only files in this backup. These sizes match for full backups. When pgBackRest compression is enabled, repository sizes reflect compressed files.
The backup reference total summarizes other backups needed to restore this backup. Use --set for the complete reference list.
Restore a Backup
Backups protect against failures, including hardware failure and data corruption. For this example, simulate corruption by removing an essential cluster file.
pg-primary ⇒ Stop the demo cluster and delete the pg_control file
Starting the cluster without this file produces an error.
pg-primary ⇒ Attempt to start the corrupted demo cluster
sudo pg_ctlcluster 17 demo start
Error: /usr/lib/postgresql/17/bin/pg_ctl /usr/lib/postgresql/17/bin/pg_ctl start -D /var/lib/postgresql/17/demo -l /var/log/postgresql/postgresql-17-demo.log -s -o -c config_file="/etc/postgresql/17/demo/postgresql.conf" exited with status 1:
postgres: could not find the database system
Expected to find it in the directory "/var/lib/postgresql/17/demo",
but could not open file "/var/lib/postgresql/17/demo/global/pg_control": No such file or directory
Examine the log output.
Run pgBackRest restore to restore the PostgreSQL cluster. First stop the cluster, which is already stopped in this example. Remove all files from its data directory.
-- An example of monitoring pgBackRest from within PostgreSQL
--
-- Use copy to export data from the pgBackRest info command into the jsonb
-- type so it can be queried directly by PostgreSQL.
-- Create monitor schema
create schema monitor;
-- Get pgBackRest info in JSON format
create function monitor.pgbackrest_info()
returns jsonb AS $$
declare
data jsonb;
begin
-- Create a temp table to hold the JSON data
create temp table temp_pgbackrest_data (data text);
-- Copy data into the table directly from the pgBackRest info command
copy temp_pgbackrest_data (data)
from program
'pgbackrest --output=json info' (format text);
select replace(temp_pgbackrest_data.data, E'\n', '\n')::jsonb
into data
from temp_pgbackrest_data;
drop table temp_pgbackrest_data;
return data;
end $$ language plpgsql;
-- Get last successful backup for each stanza
--
-- Requires the monitor.pgbackrest_info function.
with stanza as
(
select data->'name' as name,
data->'backup'->(
jsonb_array_length(data->'backup') - 1) as last_backup,
data->'archive'->(
jsonb_array_length(data->'archive') - 1) as current_archive
from jsonb_array_elements(monitor.pgbackrest_info()) as data
)
select name,
to_timestamp(
(last_backup->'timestamp'->>'stop')::numeric) as last_successful_backup,
current_archive->>'max' as last_archived_wal
from stanza;
File bundles reduce backup time and repository space. Benefits are greatest on object stores, such as S3, and filesystems with large blocks. Object stores have higher per-file creation costs. Very small files can cost as much to store as larger files.
A full backup without bundles has more than 1000 files in its backup path. Bundles substantially reduce this count. Zero-length files then have only manifest entries. Without bundles, each zero-length file is stored separately.
sudo -u postgres find /var/lib/pgbackrest/backup/demo/latest/ -type f | wc -l
5
Tune bundles with repo-bundle-size and repo-bundle-limit. The defaults should suit most cases.
Bundles usually improve efficiency, but make manual file retrieval harder. They might also be unsuitable for deduplicated storage because each full backup arranges files differently. Bundles cannot resume after interruption. Avoid a very high repo-bundle-limit.
Block Incremental
Block incremental backups store only file parts changed since the previous backup. This saves space compared with storing entire files.
Enable block incremental backups with repo-block. They work best when enabled for every backup type. File bundles must also be enabled.
Retain as many backups as practical to extend the Point-in-Time Recovery window. Account for limits such as disk space. Retention options remove backups when they are no longer needed.
pgBackRest rotates full backups according to a count or time period. Count-based retention keeps a specified number, regardless of creation times. Differential retention uses a count, but a differential always expires with its parent full backup. Incremental backups have no independent expiration policy. They expire with their parent full or differential backup. See Full Backup Retention and Differential Backup Retention for examples.
By default, pgBackRest keeps archived WAL for unexpired backups. You can change this per repository with retention-archive options, but this is not recommended. See Archive Retention.
The expire command runs automatically after each successful backup. You can also run it manually. A manual run applies each configured repository’s retention settings; --repo limits it to one repository. Use --set to expire a specific backup set. Without --repo, pgBackRest searches all repositories and expires sets that match. Every expire run also checks and applies archive retention.
Full Backup Retention
repo1-retention-full-type determines whether repo1-retention-full means a backup count or days of retention. New backups must complete before expiration. With repo1-retention-full-type=count and repo1-retention-full=2, three full backups exist before the oldest expires. With repo1-retention-full-type=time and repo1-retention-full=20, at least one full backup must be 20 days old before expiration.
Archive data does expire because WAL segments exist from before the oldest backup. These cannot recover that backup. Recovery uses WAL generated after a backup.
Full backup 20260927-101911F expires. Archive retention now follows 20260927-101932F, the oldest remaining full backup.
Differential Backup Retention
Set repo1-retention-diff to the required differential backup count. Differentials depend only on the previous full backup. Keep a changing set covering the last day or longer for fast recent restores with less total space.
With repo1-retention-diff=1, two differentials must complete before one expires. Add an incremental to demonstrate that it expires with its parent differential.
pg-primary ⇒ Perform differential and incremental backups
By default, archive expiration follows full backup expiration through repo1-retention-full. You can expire archives more aggressively to save disk space. For differential archive retention, full backups also count as differentials.
Archive expiration never removes WAL needed for backup consistency. However, PITR needs a continuous WAL stream. Use care when expiring archives beyond normal backup expiration. To inspect proposed removals, run expire with command-line dry-run.
WAL for 20260927-101935F_20260927-101939D must remain to make older backups consistent, although those backups can no longer support further PITR. Segments generated after 20260927-101935F_20260927-101939D and before 20260927-101935F_20260927-101941D are removed. Segments after the new backup 20260927-101935F_20260927-101941D remain available for PITR.
Full backups count as differentials for differential archive retention. With these settings, a new full backup retains only its own archive for PITR.
Restore
By default, restore selects the latest backup from the first repository with backups. See Quick Start - Restore a Backup. Repository order comes from pgbackrest.conf; for example, repo1 precedes repo2. Use --repo, such as --repo=1, to select a repository. Use --set to select a backup other than the latest.
For PITR with --type=time or --type=lsn, specify the target time or LSN with --target. Without --set, pgBackRest searches configured repositories in order for a backup containing that time or LSN. If none matches, --type=time uses the latest backup in the first repository with backups. For --type=lsn, it selects no backup. For other types, such as xid, use --set if the target precedes the latest backup. See Point-in-Time Recovery.
The following sections introduce additional restore command features.
File Ownership
A typical restore runs as a non-root user. All restored files belong to the executing user and group. Existing files with other ownership cause an error if pgBackRest cannot change their ownership. Have a privileged user correct the ownership before retrying.
When restore runs as root, pgBackRest attempts to recreate manifest ownership. The manifest stores user/group names, so matching names must exist locally. If a name is absent, use the PostgreSQL data directory owner or group. If that identity also lacks a name, use root.
Delta Option
Restore a Backup in Quick Start required an empty cluster directory before restore. The delta option identifies files that can remain and files that need replacement. It also removes files absent from the manifest, including divergent changes. pgBackRest calculates a SHA-1 hash for each existing file. A file whose SHA-1 differs from the backup is restored.
Use process-max to speed this operation. PostgreSQL is stopped during restore, so you can use more processes than during an online backup.
pg-primary ⇒ Stop the demo cluster, perform delta restore
Stop the cluster and restore only the test2 database. Built-in databases (template0, template1, and postgres) are always restored.
WARNING:
Recovery can fail without --type=immediate. After consistency, PostgreSQL treats zeroed pages as errors, even with full-page writes. PostgreSQL ≥ 13 can use ignore_invalid_pages to ignore invalid pages. If you use this setting, check recovery logs for invalid pages in the selected databases.
pg-primary ⇒ Restore from last backup including only the test2 database
After recovery, test2 contains all previously created tables and data.
pg-primary ⇒ Demonstrate that the test2 database was recovered
sudo -u postgres psql -c "select * from test2_table;" test2
id
----
2
(1 row)
Although recovery succeeded, test1 is inaccessible. Its files were restored as sparse, zeroed files. PostgreSQL can replay WAL into them, but empty essential files leave the database invalid. This intentionally prevents use of a database that might contain only partial data from WAL replay.
pg-primary ⇒ Attempting to connect to the test1 database will produce an error
sudo -u postgres psql -c "select * from test1_table;" test1
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL: relation mapping file "base/32768/pg_filenode.map" contains invalid data
Sparse, zeroed test1 files use space only for WAL written during recovery. Backup and recovery WAL volumes can be substantial. However, they are usually a small fraction of database size, especially for large databases that benefit most from selective restore.
The selective restore uses much less disk space for test1 than a complete restore would.
pg-primary ⇒ Show space used by test1 database after recovery
sudo -u postgres du -sh /var/lib/postgresql/17/demo/base/32768
8.0K /var/lib/postgresql/17/demo/base/32768
Only drop database can now operate on invalid test1. pgBackRest does not drop it automatically because this requires completed recovery and an accessible cluster.
pg-primary ⇒ Drop the test1 database
sudo -u postgres psql -c "drop database test1;"
DROP DATABASE
After dropping invalid test1, only test2 and the built-in databases remain.
pg-primary ⇒ List remaining databases
sudo -u postgres psql -c "select oid, datname from pg_database order by oid;"
Restore a Backup in Quick Start replayed WAL to the end of the stream. This is usually best after hardware failure. For data corruption caused by machines or people, Point-in-Time Recovery (PITR) is often more suitable.
PITR replays WAL from a backup to a specified LSN, time, transaction ID, or recovery point. Time-based recovery is often the most useful choice. This example recovers an accidentally dropped table. Use the same method for accidentally deleted data.
pg-primary ⇒ Create a table with very important data
After recording the time, drop the table. In a real incident, the exact drop time can be harder or impossible to find. Investigation should help you estimate it.
pg-primary ⇒ Drop the important table
sudo -u postgres psql -c "begin; \
drop table important_table; \
commit; \
select * from important_table;"
BEGIN
DROP TABLE
COMMITERROR: relation "important_table" does not exist
LINE 1: ...le important_table; commit; select * from important_...
^
A backup taken after the target cannot recover to that target. To demonstrate this, take an incremental backup without important_table.
[filtered 13 lines of output]
LOG: database system is ready to accept read-only connections
LOG: redo done at 0/1A000120 system usage: CPU: user: 0.00 s, system: 0.00 s, elapsed: 0.03 s
FATAL: recovery ended before configured recovery target was reached
LOG: startup process (PID 1440) exited with exit code 1
LOG: terminating any other active server processes
LOG: database system is shut down
Let pgBackRest select a backup that completed before the target time and can recover to it.
NOTE:
pgBackRest cannot automatically select a backup when the restore type is xid or name.
pg-primary ⇒ Restore the demo cluster to 2026-08-17 04:51:24.23782+00
[filtered 9 lines of output]
# Recovery settings generated by pgBackRest restore on 2026-09-27 10:20:03
restore_command = 'pgbackrest --stanza=demo archive-get %f "%p"'
recovery_target_time = '2026-09-27 10:19:58.808792+00'
recovery_target_action = 'promote'
pgBackRest wrote recovery settings to postgresql.auto.conf, so start PostgreSQL immediately. PostgreSQL uses %f for the required WAL segment and %p for its destination. After recovery, the table exists and accepts queries again.
pg-primary ⇒ Start PostgreSQL and check that the important table exists
[filtered 7 lines of output]
LOG: restored log file "00000004.history" from archive
LOG: restored log file "000000040000000000000019" from archive
LOG: starting point-in-time recovery to 2026-09-27 10:19:58.808792+00
LOG: restored log file "00000003.history" from archive
LOG: redo starts at 0/19000028
[filtered 2 lines of output]
LOG: database system is ready to accept read-only connections
LOG: restored log file "00000004000000000000001A" from archive
LOG: recovery stopping before commit of transaction 748, time 2026-09-27 10:20:00.041047+00
LOG: redo done at 0/1901CC00 system usage: CPU: user: 0.00 s, system: 0.01 s, elapsed: 0.07 s
LOG: last completed transaction was at log time 2026-09-27 10:19:57.537628+00
LOG: restored log file "000000040000000000000019" from archive
LOG: selected new timeline ID: 5
[filtered 5 lines of output]
Delete a Stanza
The stanza-delete command removes repository data for a stanza.
WARNING:
Use this command with care. It permanently removes every backup and archive for the specified stanza from the pgBackRest repository.
To delete a stanza:
Shut down the PostgreSQL cluster associated with the stanza (or use –force to override).
Run the stop command on the host where the stanza-delete command will be run.
Run the stanza-delete command.
After the command succeeds, remove the stanza from all applicable pgBackRest configuration files and environment variables.
Delete a stanza from one repository at a time. For multiple repositories, repeat stanza-delete with --repo for each repository.
pg-primary ⇒ Stop PostgreSQL cluster to be removed
For compatibility, repo is optional when only repo1 is configured. It is required when the only repository has another index, such as repo2. This prevents command failures if another repository is added later.
archive-push sends WAL to all configured repositories. If one is unreachable, it still sends WAL to the others. Enable archive-async=y for effective independent progress. Otherwise, the other repositories can advance only one segment beyond the unreachable repository. If WAL cannot reach any repository, PostgreSQL keeps it in pg_wal. This can fill the volume.
Schedule backups separately for each repository. This lets you vary backup types and retention. Specify a repository for restores as well. A repository with low latency or cost is usually preferable, even with longer recovery time. Test restores to determine which is most efficient.
Azure-Compatible Object Store Support
pgBackRest supports repositories in Azure-compatible object stores. Create the container first; pgBackRest does not create it. You can use the container root (/). Usually, prefer a subpath so object-store logs and other data can share the container without conflicts.
WARNING:
Do not enable “hierarchical namespace” as this will cause errors during expire.
P00 INFO: backup command begin 2.59.2: --exec-id=1670-de551bc3 --log-level-console=info --no-log-timestamp --pg1-path=/var/lib/postgresql/17/demo --repo=2 --repo2-azure-account=<redacted> --repo2-azure-container=demo-container --repo2-azure-key=<redacted> --repo1-block --repo1-bundle --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=/var/lib/pgbackrest --repo2-path=/demo-repo --repo1-retention-diff=2 --repo1-retention-full=2 --repo2-retention-full=4 --repo2-type=azure --stanza=demo --start-fast
P00 WARN: no prior backup exists, incr backup has been changed to full
P00 INFO: execute backup start: backup begins after the requested immediate checkpoint completes
P00 INFO: backup start archive = 00000005000000000000001B, lsn = 0/1B000028
[filtered 3 lines of output]
P00 INFO: check archive for segment(s) 00000005000000000000001B:00000005000000000000001B
P00 INFO: new backup label = 20260927-102014F
P00 INFO: full backup size = 29.2MB, file total = 1265
P00 INFO: backup command end: completed successfully
P00 INFO: expire command begin 2.59.2: --exec-id=1670-de551bc3 --log-level-console=info --no-log-timestamp --repo=2 --repo2-azure-account=<redacted> --repo2-azure-container=demo-container --repo2-azure-key=<redacted> --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=/var/lib/pgbackrest --repo2-path=/demo-repo --repo1-retention-diff=2 --repo1-retention-full=2 --repo2-retention-full=4 --repo2-type=azure --stanza=demo
S3-Compatible Object Store Support
pgBackRest supports repositories in S3-compatible object stores. Create the bucket first; pgBackRest does not create it. You can use the bucket root (/). Usually, prefer a subpath so object-store logs and other data can share the bucket without conflicts.
Set the region and endpoint for the bucket location. These examples use us-east-1.
Create a role for pgBackRest and restrict bucket permissions as much as possible. For an AWS instance-associated role, set repo3-s3-key-type=auto to retrieve temporary credentials automatically. You then do not need explicit keys in /etc/pgbackrest/pgbackrest.conf.
This sample Amazon S3 policy will restrict all reads and writes to the bucket and repository path.
P00 INFO: backup command begin 2.59.2: --exec-id=1862-9e493c8b --log-level-console=info --no-log-timestamp --pg1-path=/var/lib/postgresql/17/demo --process-max=4 --repo=4 --repo2-azure-account=<redacted> --repo2-azure-container=demo-container --repo2-azure-key=<redacted> --repo1-block --repo1-bundle --repo4-bundle --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=/var/lib/pgbackrest --repo2-path=/demo-repo --repo3-path=/demo-repo --repo4-path=/demo-repo --repo1-retention-diff=2 --repo1-retention-full=2 --repo2-retention-full=4 --repo3-retention-full=4 --repo3-s3-bucket=demo-bucket --repo3-s3-endpoint=s3.us-east-1.amazonaws.com --repo3-s3-key=<redacted> --repo3-s3-key-secret=<redacted> --repo3-s3-region=us-east-1 --repo4-sftp-host=sftp-server --repo4-sftp-host-key-hash-type=sha1 --repo4-sftp-host-user=pgbackrest --repo4-sftp-private-key-file=/var/lib/postgresql/.ssh/id_rsa_sftp --repo4-sftp-public-key-file=/var/lib/postgresql/.ssh/id_rsa_sftp.pub --repo2-type=azure --repo3-type=s3 --repo4-type=sftp --stanza=demo --start-fast
P00 WARN: option 'repo4-retention-full' is not set for 'repo4-retention-full-type=count', the repository may run out of space
HINT: to retain full backups indefinitely (without warning), set option 'repo4-retention-full' to the maximum.
P00 WARN: no prior backup exists, incr backup has been changed to full
P00 INFO: execute backup start: backup begins after the requested immediate checkpoint completes
P00 INFO: backup start archive = 00000005000000000000001E, lsn = 0/1E000028
[filtered 3 lines of output]
P00 INFO: check archive for segment(s) 00000005000000000000001E:00000005000000000000001F
P00 INFO: new backup label = 20260927-102048F
P00 INFO: full backup size = 29.2MB, file total = 1265
P00 INFO: backup command end: completed successfully
P00 INFO: expire command begin 2.59.2: --exec-id=1862-9e493c8b --log-level-console=info --no-log-timestamp --repo=4 --repo2-azure-account=<redacted> --repo2-azure-container=demo-container --repo2-azure-key=<redacted> --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=/var/lib/pgbackrest --repo2-path=/demo-repo --repo3-path=/demo-repo --repo4-path=/demo-repo --repo1-retention-diff=2 --repo1-retention-full=2 --repo2-retention-full=4 --repo3-retention-full=4 --repo3-s3-bucket=demo-bucket --repo3-s3-endpoint=s3.us-east-1.amazonaws.com --repo3-s3-key=<redacted> --repo3-s3-key-secret=<redacted> --repo3-s3-region=us-east-1 --repo4-sftp-host=sftp-server --repo4-sftp-host-key-hash-type=sha1 --repo4-sftp-host-user=pgbackrest --repo4-sftp-private-key-file=/var/lib/postgresql/.ssh/id_rsa_sftp --repo4-sftp-public-key-file=/var/lib/postgresql/.ssh/id_rsa_sftp.pub --repo2-type=azure --repo3-type=s3 --repo4-type=sftp --stanza=demo
P00 INFO: expire command end: completed successfully
GCS-Compatible Object Store Support
pgBackRest supports repositories in GCS-compatible object stores. Create the bucket first; pgBackRest does not create it. You can use the bucket root (/). Usually, prefer a subpath so object-store logs and other data can share the bucket without conflicts.
On GCE, set repo5-gcs-key-type=auto to authenticate through the instance service account.
Run commands as you would for a repository on a local disk.
GCS file creation is relatively slow. Enable file bundling to improve backup/restore performance.
Target Time for Repository
Set the point in time at which commands read a repository on versioned storage. This lets you recover data deleted or corrupted by user error or malware.
S3, GCS, and Azure support versioned storage, but usually disable it by default. In addition to versioning, consider S3 object locking or GCS and Azure soft delete.
When you specify repo-target-time, you must also specify repo. Some repository types probably will not support versioning. Recovery usually targets one repository.
Storage timestamps must be <= the specified timestamp. pgBackRest truncates milliseconds from the specified timestamp.
Delete the S3 repository demo stanza to demonstrate recovery from versioned storage.
sudo -u postgres pgbackrest --stanza=demo --repo=3 info
stanza: demo
status: error (missing stanza path)
Versioned storage lets you read the repository before deletion. Finding the target time can be difficult. Here, use the deletion time of backup.info to identify when the stanza was deleted.
pg-primary ⇒ List versions of backup.info in the bucket
Quickstart suits simple installations. Enterprise installations commonly use a separate repository host for backups and WAL archives. This reduces the effect of database host failures on backup data. Also consider conventional backup software for the repository host.
On each PostgreSQL host, set pg1-path to the local cluster path and leave pg1-host unset. On the repository host, configure pg-host connections to the primary and any standby hosts. Only the repository host configuration should list multiple PostgreSQL hosts. Either index can identify the primary or standby; for example, pg1-path/pg1-host and pg2-path/pg2-host can appear in either order.
Installation
Create a host named repository to store cluster backups.
NOTE:
The pgBackRest version installed on the repository host must exactly match the version installed on the PostgreSQL host.
Create pgbackrest as the repository owner. Any user can own it, but avoid postgres, if present, to prevent confusion.
NOTE:
A pgBackRest package might install logrotate configuration, such as /etc/logrotate.d/pgbackrest, with a su directive like su postgres postgres. Files in /var/log/pgbackrest belong to the user running pgBackRest, here pgbackrest. Update su to that user. Otherwise, logrotate fails with a permission error.
Prefer package installation to a source build. Packages usually perform the remaining steps in this section. If a package omits a directory or sets incorrect permissions, create the directory or correct its permissions manually.
Debian/Ubuntu packages for pgBackRest are available at apt.postgresql.org.
If your distribution or version has no package, build from source and follow these manual installation steps.
On the database host, configure the repository host and user. repo1-host-user defaults to pgbackrest. If postgres performs restores on the repository host, preferably prevent it from also performing backups. It can read the repository directly if it belongs to the pgbackrest group.
pgBackRest can compress and transfer data in parallel. Set the process count with --process-max.
Usually, allocate no more than 25% of available CPUs to backup. Regular backups do not need maximum speed. Avoid reducing database performance where possible.
Restore should use all available CPUs because PostgreSQL is stopped and usually no other critical work runs on that host. If the host has multiple clusters, account for them when setting parallelism.
Multiple processes should speed up the last backup. For very small backups, the difference might be small. Time savings increase with database size.
Starting and Stopping
Prevent test clusters from writing to pgBackRest repositories with stop. This includes standbys promoted for testing and test clusters restored from production backups.
stop blocks these write commands: archive-push, backup, expire, stanza-create, and stanza-upgrade. The exception is stanza-delete; see Delete a Stanza.
P00 WARN: unable to check pg1: [StopError] raised from remote-0 ssh protocol on 'pg-primary': stop file exists for all stanzas
P00 ERROR: [056]: unable to find primary cluster - cannot proceed
HINT: are all available clusters in recovery?
Use --force to terminate running pgBackRest write commands. This also terminates asynchronous archive-get, although it restarts if PostgreSQL needs it. Repeating stop when pgBackRest is already stopped produces a warning.
pg-primary ⇒ Stop the pgBackRest services again
sudo -u postgres pgbackrest stop
P00 WARN: stop file already exists for all stanzas
Use start to permit pgBackRest write commands again. Previously interrupted commands do not restart automatically.
pg-primary ⇒ Start pgBackRest write commands
sudo -u postgres pgbackrest start
You can also stop pgBackRest for one stanza.
pg-primary ⇒ Stop pgBackRest write commands for the demo stanza
sudo -u postgres pgbackrest --stanza=demo stop
New pgBackRest write commands cannot run for this stanza.
P00 WARN: unable to check pg1: [StopError] raised from remote-0 ssh protocol on 'pg-primary': stop file exists for stanza demo
P00 ERROR: [056]: unable to find primary cluster - cannot proceed
HINT: are all available clusters in recovery?
When starting write commands for one stanza, specify that stanza again.
pg-primary ⇒ Start pgBackRest write commands for the demo stanza
sudo -u postgres pgbackrest --stanza=demo start
Replication
Replication creates standby copies of a PostgreSQL primary cluster. Standbys distribute read load and provide redundancy if the primary host fails.
Installation
Create a host named pg-standby for the standby.
Prefer package installation to a source build. Packages usually perform the remaining steps in this section. If a package omits a directory or sets incorrect permissions, create the directory or correct its permissions manually.
Debian/Ubuntu packages for pgBackRest are available at apt.postgresql.org.
If your distribution or version has no package, build from source and follow these manual installation steps.
Create the demo cluster to generate PostgreSQL configuration files. The restore will overwrite the cluster.
pg-standby ⇒ Create demo cluster
sudo pg_createcluster 17 demo
Create the standby with restore.
IMPORTANT:
If promotion is for testing or reporting rather than a new primary, disable archiving. Use --archive-mode=off or set archive_mode=off in postgresql.conf. Otherwise, the cluster can add conflicting WAL to the repository and complicate restores.
P00 INFO: check command begin 2.59.2: --exec-id=515-943c4c3c --log-level-console=info --log-level-file=detail --no-log-timestamp --pg1-path=/var/lib/postgresql/17/demo --repo1-host=repository --stanza=demo
P00 INFO: check repo1 (standby)
P00 INFO: switch wal not performed because this is a standby
P00 INFO: check command end: completed successfully
Streaming Replication
Streaming replication connects directly to the primary and applies changes as they occur. This reduces primary-to-standby lag compared with archive-only replication.
Streaming replication requires a user with the replication privilege.
Update pg_hba.conf to allow the standby to connect as the replication user. Replace the example IP address with your pg-standby address. Reload configuration after the change.
pg-primary ⇒ Create pg_hba.conf entry for replication user
# Do not edit this file manually!
# It will be overwritten by the ALTER SYSTEM command.
# Recovery settings generated by pgBackRest restore on 2026-09-27 10:19:18
restore_command = 'pgbackrest --stanza=demo archive-get %f "%p"'
# Recovery settings generated by pgBackRest restore on 2026-09-27 10:19:43
restore_command = 'pgbackrest --stanza=demo archive-get %f "%p"'
# Recovery settings generated by pgBackRest restore on 2026-09-27 10:20:03
restore_command = 'pgbackrest --stanza=demo archive-get %f "%p"'
# Removed by pgBackRest restore on 2026-09-27 10:20:57 # recovery_target_time = '2026-09-27 10:19:58.808792+00'
# Removed by pgBackRest restore on 2026-09-27 10:20:57 # recovery_target_action = 'promote'
# Recovery settings generated by pgBackRest restore on 2026-09-27 10:20:57
restore_command = 'pgbackrest --repo=3 --repo-target-time="2026-09-27 10:20:43+00" --stanza=demo archive-get %f "%p"'
# Recovery settings generated by pgBackRest restore on 2026-09-27 10:21:22
restore_command = 'pgbackrest --stanza=demo archive-get %f "%p"'
# Recovery settings generated by pgBackRest restore on 2026-09-27 10:22:05
primary_conninfo = 'host=172.17.0.6 port=5432 user=replicator'
restore_command = 'pgbackrest --stanza=demo archive-get %f "%p"'
NOTE:
pgBackRest wrote primary_conninfo to postgresql.auto.conf because pgbackrest.conf defines it as a recovery-option. To preserve an existing postgresql.auto.conf, run restore with --type=preserve.
pg-standby ⇒ Start PostgreSQL
sudo pg_ctlcluster 17 demo start
Check the PostgreSQL log to confirm that streaming replication started.
pg-standby ⇒ Examine the PostgreSQL log output for log messages indicating success
[filtered 13 lines of output]
LOG: consistent recovery state reached at 0/25000088
LOG: database system is ready to accept read-only connections
LOG: started streaming WAL from primary at 0/27000000 on timeline 7
New tables on pg-primary now appear quickly on pg-standby without pg_switch_wal().
message | current_timestamp
----------------+------------------------------
Important Data | 2026-09-27 10:22:11.89181+00
(1 row)
Multiple Stanzas
pgBackRest supports multiple stanzas, commonly with one shared repository host.
Installation
Create a host named pg-alt for the new primary.
Prefer package installation to a source build. Packages usually perform the remaining steps in this section. If a package omits a directory or sets incorrect permissions, create the directory or correct its permissions manually.
Debian/Ubuntu packages for pgBackRest are available at apt.postgresql.org.
If your distribution or version has no package, build from source and follow these manual installation steps.
Configure the spool path and enable asynchronous archiving. This reduces remote-storage connections. Set process-max for parallel operations and further performance improvements. Keep it low enough to preserve normal database performance.
pg-primary:/etc/pgbackrest/pgbackrest.conf⇒ Configure the spool path and asynchronous archiving
Set process-max in command-specific sections so it does not affect backup or restore. You can give archive-push and archive-get different values.
For this demonstration, interrupt streaming replication so PostgreSQL must fetch WAL through restore_command.
pg-primary ⇒ Break streaming replication by changing the replication password
sudo -u postgres psql -c "alter user replicator password 'bogus'"
ALTER ROLE
pg-standby ⇒ Restart standby to break connection
sudo pg_ctlcluster 17 demo restart
Archive Push
Asynchronous archive-push transfers WAL archiving to separate processes to improve throughput. It finds ready segments beyond the one PostgreSQL currently requests through archive_command. It copies WAL directly from pg_xlog/pg_wal to the archive. The archive_command returns success only after the requested segment is safely stored.
The spool path contains current WAL archive status. Status files are usually empty and use little I/O and space, at most a few MB. pgBackRest can recreate all this information. You do not need to preserve the directory when moving the cluster to new hardware.
IMPORTANT:
The original asynchronous implementation copied WAL to the spool directory before compression and transfer. The newer implementation reads WAL directly from pg_xlog. If you used asynchronous archiving in v1.12 or earlier, read the v1.13 release notes carefully before upgrading.
Monitor asynchronous activity in [stanza]-archive-push-async.log. To test it, push several WAL segments quickly.
-------------------PROCESS START-------------------
P00 INFO: archive-push:async command begin 2.59.2: [/var/lib/postgresql/17/demo/pg_wal] --archive-async --exec-id=2579-4f897cce --log-level-console=off --log-level-file=detail --log-level-stderr=off --no-log-timestamp --pg1-path=/var/lib/postgresql/17/demo --process-max=2 --repo1-host=repository --spool-path=/var/spool/pgbackrest --stanza=demo
P00 INFO: push 1 WAL file(s) to archive: 000000070000000000000028
P01 DETAIL: pushed WAL file '000000070000000000000028' to the archive
P00 INFO: archive-push:async command end: completed successfully
-------------------PROCESS START-------------------
P00 INFO: archive-push:async command begin 2.59.2: [/var/lib/postgresql/17/demo/pg_wal] --archive-async --exec-id=2596-db8c73d8 --log-level-console=off --log-level-file=detail --log-level-stderr=off --no-log-timestamp --pg1-path=/var/lib/postgresql/17/demo --process-max=2 --repo1-host=repository --spool-path=/var/spool/pgbackrest --stanza=demo
P00 INFO: push 5 WAL file(s) to archive: 000000070000000000000029...00000007000000000000002D
P01 DETAIL: pushed WAL file '000000070000000000000029' to the archive
P02 DETAIL: pushed WAL file '00000007000000000000002A' to the archive
P02 DETAIL: pushed WAL file '00000007000000000000002C' to the archive
P01 DETAIL: pushed WAL file '00000007000000000000002B' to the archive
P02 DETAIL: pushed WAL file '00000007000000000000002D' to the archive
P00 INFO: archive-push:async command end: completed successfully
Archive Get
Asynchronous archive-get keeps a local WAL queue to improve throughput. If a requested segment is absent, it fetches that segment and enough consecutive segments to fill the queue. archive-get-queue-max controls maximum size. When the queue falls below half full, pgBackRest fetches more WAL to refill it.
Asynchronous operation helps most with high WAL volumes or high-latency repository connections, such as S3 and other object stores. For high latency, consider increasing process-max.
Monitor asynchronous activity in [stanza]-archive-get-async.log.
-------------------PROCESS START-------------------
P00 INFO: archive-get:async command begin 2.59.2: [000000070000000000000024, 000000070000000000000025, 000000070000000000000026, 000000070000000000000027, 000000070000000000000028, 000000070000000000000029, 00000007000000000000002A, 00000007000000000000002B] --archive-async --exec-id=736-1978b097 --log-level-console=off --log-level-file=detail --log-level-stderr=off --no-log-timestamp --pg1-path=/var/lib/postgresql/17/demo --process-max=2 --repo1-host=repository --spool-path=/var/spool/pgbackrest --stanza=demo
P00 INFO: get 8 WAL file(s) from archive: 000000070000000000000024...00000007000000000000002B
P01 DETAIL: found 000000070000000000000024 in the repo1: 17-1 archive
P02 DETAIL: found 000000070000000000000025 in the repo1: 17-1 archive
P01 DETAIL: found 000000070000000000000026 in the repo1: 17-1 archive
P02 DETAIL: found 000000070000000000000027 in the repo1: 17-1 archive
P00 DETAIL: unable to find 000000070000000000000028 in the archive
P00 INFO: archive-get:async command end: completed successfully
[filtered 14 lines of output]
P00 INFO: archive-get:async command begin 2.59.2: [000000070000000000000028, 000000070000000000000029, 00000007000000000000002A, 00000007000000000000002B, 00000007000000000000002C, 00000007000000000000002D, 00000007000000000000002E, 00000007000000000000002F] --archive-async --exec-id=789-38affa51 --log-level-console=off --log-level-file=detail --log-level-stderr=off --no-log-timestamp --pg1-path=/var/lib/postgresql/17/demo --process-max=2 --repo1-host=repository --spool-path=/var/spool/pgbackrest --stanza=demo
P00 INFO: get 8 WAL file(s) from archive: 000000070000000000000028...00000007000000000000002F
P02 DETAIL: found 000000070000000000000029 in the repo1: 17-1 archive
P01 DETAIL: found 000000070000000000000028 in the repo1: 17-1 archive
P02 DETAIL: found 00000007000000000000002A in the repo1: 17-1 archive
P01 DETAIL: found 00000007000000000000002B in the repo1: 17-1 archive
P02 DETAIL: found 00000007000000000000002C in the repo1: 17-1 archive
P01 DETAIL: found 00000007000000000000002D in the repo1: 17-1 archive
P00 DETAIL: unable to find 00000007000000000000002E in the archive
P00 INFO: archive-get:async command end: completed successfully
[filtered 11 lines of output]
pg-primary ⇒ Fix streaming replication by changing the replication password
sudo -u postgres psql -c "alter user replicator password 'jw8s0F4'"
ALTER ROLE
Backup from a Standby
pgBackRest can back up from a standby instead of the primary. Configure pg-standby and enable backup-standby. If several standbys are configured, it uses the first running standby found.
repository:/etc/pgbackrest/pgbackrest.conf⇒ Configure pg2-host/pg2-host-user and pg2-path
Backup requires both the primary and standby databases. Most files come from the standby to reduce primary load. Configure hosts in any order. pgBackRest detects their roles automatically.
[filtered 2 lines of output]
P00 INFO: execute backup start: backup begins after the requested immediate checkpoint completes
P00 INFO: backup start archive = 00000007000000000000002F, lsn = 0/2F000028
P00 INFO: wait for replay on the standby to reach 0/2F000028
P00 INFO: replay on the standby reached 0/2F000028
P00 INFO: check archive for prior segment 00000007000000000000002E
P01 DETAIL: backup file pg-primary:/var/lib/postgresql/17/demo/global/pg_control (8KB, 0.53%) checksum 7d84baa1f0b16cc8652b16c41ef075f5df25d016
P01 DETAIL: match file from prior backup pg-primary:/var/lib/postgresql/17/demo/pg_logical/replorigin_checkpoint (8B, 0.53%) checksum 347fc8f2df71bd4436e38bd1516ccd7ea0d46532
P02 DETAIL: backup file pg-standby:/var/lib/postgresql/17/demo/base/5/1249 (448KB, 30.16%) checksum 3b6f5ca3b766aa5972894958f6b2f4d0d98f0228
[filtered 1278 lines of output]
This incremental backup copies most files from pg-standby and only a few from pg-primary.
A standby backup is identical to a primary backup. pgBackRest starts and stops the backup on pg-primary. It copies replicated files from pg-standby and the remaining files from pg-primary. Thus, the backup includes primary logs and statistics.
Upgrading PostgreSQL
Immediately after a PostgreSQL major version upgrade, update pg-path in all pgBackRest configurations to the new database location. Then run stanza-upgrade. It upgrades the stanza in every repository configured on the host. If the database is offline, use --no-online.
These steps outline a primary and standby upgrade to demonstrate pgBackRest reconfiguration. They are not a complete PostgreSQL upgrade guide. Take a backup before upgrading.
pg-primary ⇒ Stop old cluster
sudo pg_ctlcluster 17 demo stop
Stop the old standby cluster. You will restore it from the upgraded cluster.
pg-standby ⇒ Stop old cluster
sudo pg_ctlcluster 17 demo stop
Create the new cluster and upgrade it.
pg-primary ⇒ Create new cluster and perform the upgrade
[filtered 44 lines of output]
Checking for extension updates ok
Upgrade Complete
----------------
Some statistics are not transferred by pg_upgrade.
[filtered 4 lines of output]
Run check on the repository host. The standby is stopped, so expect a warning. This verifies that the repository knows about the standby and has correct primary configuration.
repository ⇒ Check configuration
sudo -u pgbackrest pgbackrest --stanza=demo check
P00 WARN: unable to check pg2: [DbConnectError] raised from remote-0 ssh protocol on 'pg-standby': unable to connect to 'dbname='postgres' port=5432': connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: No such file or directory
Is the server running locally and accepting connections on that socket?
Take a full backup of the new cluster, then restore the standby from it. Requests for incr or diff automatically change to full.