<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Pgbackrest on Citizix, The Best blog for Linux, Opensource, Devops, Cloud and all things awesome tech.</title><link>https://citizix.com/tags/pgbackrest/</link><description>Recent content in Pgbackrest on Citizix, The Best blog for Linux, Opensource, Devops, Cloud and all things awesome tech.</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><copyright>Citizix, Ltd.</copyright><lastBuildDate>Wed, 28 Oct 2026 11:58:17 +0300</lastBuildDate><atom:link href="https://citizix.com/tags/pgbackrest/index.xml" rel="self" type="application/rss+xml"/><item><title>pgBackRest Guide: PostgreSQL Backup, Restore and PITR</title><link>https://citizix.com/pgbackrest-postgresql-backup-restore-pitr-guide/</link><pubDate>Wed, 28 Oct 2026 08:09:44 +0000</pubDate><guid>https://citizix.com/pgbackrest-postgresql-backup-restore-pitr-guide/</guid><description>&lt;p&gt;&lt;strong&gt;pgBackRest&lt;/strong&gt; is the backup tool most production PostgreSQL teams end up with once &lt;code&gt;pg_dump&lt;/code&gt;
stops scaling. It takes physical backups of the whole cluster, archives every WAL segment, and
restores to any second inside your retention window: point-in-time recovery (PITR). It handles
multi-terabyte databases with parallel compression, encryption, block-level incrementals and
object storage like S3.&lt;/p&gt;
&lt;p&gt;This guide starts with the concepts, builds a working setup on Rocky Linux / AlmaLinux 9 with
PostgreSQL 17, and then moves to the advanced parts: multiple repositories, asynchronous
archiving, retention tuning, PITR, partial restores, standbys and monitoring. Every configuration
option and command flag used is explained where it first appears.&lt;/p&gt;
&lt;p&gt;The commands and option names match &lt;strong&gt;pgBackRest 2.60&lt;/strong&gt;. Check &lt;code&gt;pgbackrest version&lt;/code&gt; on your host;
older releases lack some options (block incremental needs 2.46 or later).&lt;/p&gt;
&lt;h2 id="pg_dump-vs-pgbackrest-logical-vs-physical-backups"&gt;pg_dump vs pgBackRest: Logical vs Physical Backups
&lt;/h2&gt;&lt;p&gt;&lt;a class="link" href="https://citizix.com/how-to-backup-and-restore-postgres-database/" &gt;&lt;code&gt;pg_dump&lt;/code&gt;&lt;/a&gt; produces a &lt;strong&gt;logical&lt;/strong&gt; backup: SQL or
a custom archive you replay into a running server. It is perfect for moving one database between
versions, but a restore re-runs every &lt;code&gt;INSERT&lt;/code&gt; and rebuilds every index, and you can only go back
to the moment the dump started.&lt;/p&gt;
&lt;p&gt;pgBackRest takes a &lt;strong&gt;physical&lt;/strong&gt; backup: a copy of the data directory&amp;rsquo;s files, plus the
write-ahead log (WAL). That gives you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Fast restores&lt;/strong&gt;: files are copied back, not replayed as SQL.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PITR&lt;/strong&gt;: replay WAL to any moment, e.g. one second before someone ran &lt;code&gt;DELETE&lt;/code&gt; without a &lt;code&gt;WHERE&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Incrementals&lt;/strong&gt;: after the first full, only changed files (or blocks) are copied.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The trade-off: a physical backup restores to the &lt;strong&gt;same PostgreSQL major version&lt;/strong&gt; and the same
architecture. Use &lt;code&gt;pg_dump&lt;/code&gt; for version migrations, pgBackRest for disaster recovery.&lt;/p&gt;
&lt;h2 id="how-pgbackrest-works"&gt;How pgBackRest Works
&lt;/h2&gt;&lt;p&gt;A usable physical backup needs two things.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;A base backup.&lt;/strong&gt; pgBackRest tells PostgreSQL a backup is starting (&lt;code&gt;pg_backup_start&lt;/code&gt;),
copies the data directory while the database keeps running, then calls &lt;code&gt;pg_backup_stop&lt;/code&gt;.
Files copied mid-write are inconsistent on their own.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The WAL archive.&lt;/strong&gt; PostgreSQL writes every change to WAL in 16 MB segments. With
&lt;code&gt;archive_mode=on&lt;/code&gt;, PostgreSQL hands each finished segment to &lt;code&gt;archive_command&lt;/code&gt;, which is
&lt;code&gt;pgbackrest archive-push&lt;/code&gt;. The WAL generated during the backup is what makes it consistent;
the WAL generated after it is what makes PITR possible.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A restore copies a base backup into place, writes a &lt;code&gt;restore_command&lt;/code&gt; (&lt;code&gt;pgbackrest archive-get&lt;/code&gt;)
into the restored config, and starts PostgreSQL. PostgreSQL replays WAL from the archive until it
reaches the target you chose, or the end of the archive.&lt;/p&gt;
&lt;h3 id="key-terms"&gt;Key Terms
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Term&lt;/th&gt;
					&lt;th&gt;Meaning&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Stanza&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;The backup configuration for one PostgreSQL cluster: its data directory, and where its backups go. Named in &lt;code&gt;[brackets]&lt;/code&gt; in the config.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Repository (repo)&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Where backups and WAL are stored: a local path, S3, Azure, GCS, SFTP, or a remote host. Numbered &lt;code&gt;repo1&lt;/code&gt;, &lt;code&gt;repo2&lt;/code&gt;, &amp;hellip;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Full backup&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;A complete copy of the data directory. Label ends in &lt;code&gt;F&lt;/code&gt;, e.g. &lt;code&gt;20261024-210001F&lt;/code&gt;.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Differential (diff)&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Files changed since the last &lt;strong&gt;full&lt;/strong&gt;. Label ends in &lt;code&gt;D&lt;/code&gt;. Restoring needs the full plus this diff.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Incremental (incr)&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Files changed since the last backup of &lt;strong&gt;any&lt;/strong&gt; type. Label ends in &lt;code&gt;I&lt;/code&gt;. Restoring needs the full, possibly a diff, and every incr in the chain.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Expire&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;Removing backups (and the WAL only they need) beyond the retention policy.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Backup set&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;One backup, identified by its label.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="step-1-install-pgbackrest"&gt;Step 1: Install pgBackRest
&lt;/h2&gt;&lt;p&gt;This guide assumes PostgreSQL 17 from the PGDG repository, set up as in
&lt;a class="link" href="https://citizix.com/how-to-install-and-configure-postgres-17-on-rocky-alma-linux-9/" &gt;How to Install and Configure Postgres 17 on Rocky/Alma Linux 9&lt;/a&gt;.
pgBackRest is in the same repository (&lt;code&gt;pgdg-common&lt;/code&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo dnf install -y pgbackrest
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pgbackrest version
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On Debian/Ubuntu with the &lt;code&gt;apt.postgresql.org&lt;/code&gt; repository:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt install -y pgbackrest
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The package creates the directories pgBackRest uses by default:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Path&lt;/th&gt;
					&lt;th&gt;Purpose&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;/etc/pgbackrest/pgbackrest.conf&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Main config file&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;/etc/pgbackrest/conf.d/&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Extra &lt;code&gt;*.conf&lt;/code&gt; files, merged into the main one&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;/var/log/pgbackrest/&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Per-command log files&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;/var/spool/pgbackrest/&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Spool for asynchronous archiving&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;/var/lib/pgbackrest/&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Default local repository path&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;pgBackRest refuses to run as root by default (&lt;code&gt;allow-root=n&lt;/code&gt;). Run every command as the
&lt;code&gt;postgres&lt;/code&gt; user: &lt;code&gt;sudo -u postgres pgbackrest ...&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="step-2-understand-the-configuration-file"&gt;Step 2: Understand the Configuration File
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;pgbackrest.conf&lt;/code&gt; is an INI file. Sections set options for different scopes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[global]&lt;/code&gt;: applies to every stanza and command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[global:&amp;lt;command&amp;gt;]&lt;/code&gt;: applies to one command only, e.g. &lt;code&gt;[global:archive-push]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[&amp;lt;stanza&amp;gt;]&lt;/code&gt;: applies to one stanza, e.g. &lt;code&gt;[main]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[&amp;lt;stanza&amp;gt;:&amp;lt;command&amp;gt;]&lt;/code&gt;: one stanza and one command.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Every option can also be passed on the command line (&lt;code&gt;--process-max=4&lt;/code&gt;) or as an environment
variable (&lt;code&gt;PGBACKREST_PROCESS_MAX=4&lt;/code&gt;). The command line wins over the environment, which wins
over the file. Options that refer to a repository or a PostgreSQL instance carry an index:
&lt;code&gt;repo1-path&lt;/code&gt;, &lt;code&gt;repo2-path&lt;/code&gt;, &lt;code&gt;pg1-path&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="step-3-a-first-configuration-with-a-local-repository"&gt;Step 3: A First Configuration with a Local Repository
&lt;/h2&gt;&lt;p&gt;Start with the simplest possible setup: one stanza, repository on a local disk. (In production,
put the repository on different hardware. Step 9 moves it to S3.)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# /etc/pgbackrest/pgbackrest.conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[global]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo1-path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/var/lib/pgbackrest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo1-retention-full&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;log-level-console&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;info&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;log-level-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;detail&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;start-fast&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;y&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[main]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;pg1-path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/var/lib/pgsql/17/data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What each option does:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Option&lt;/th&gt;
					&lt;th&gt;Meaning&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;repo1-path&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Where repo1 stores backups and WAL. Default &lt;code&gt;/var/lib/pgbackrest&lt;/code&gt;. For object stores, a path inside the bucket.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;repo1-retention-full&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;How many full backups to keep (see Step 8). With no retention set, pgBackRest warns and keeps everything.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;log-level-console&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;What prints to the terminal: &lt;code&gt;off&lt;/code&gt;, &lt;code&gt;error&lt;/code&gt;, &lt;code&gt;warn&lt;/code&gt; (default), &lt;code&gt;info&lt;/code&gt;, &lt;code&gt;detail&lt;/code&gt;, &lt;code&gt;debug&lt;/code&gt;, &lt;code&gt;trace&lt;/code&gt;. &lt;code&gt;info&lt;/code&gt; shows progress.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;log-level-file&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;What goes to &lt;code&gt;/var/log/pgbackrest/&amp;lt;stanza&amp;gt;-&amp;lt;command&amp;gt;.log&lt;/code&gt;. Default &lt;code&gt;info&lt;/code&gt;; &lt;code&gt;detail&lt;/code&gt; records every file copied.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;start-fast&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Default &lt;code&gt;n&lt;/code&gt;. With &lt;code&gt;y&lt;/code&gt;, the backup forces an immediate checkpoint instead of waiting for the next scheduled one (up to &lt;code&gt;checkpoint_timeout&lt;/code&gt;, 5 min by default).&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;pg1-path&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;The data directory of the cluster this stanza backs up.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The &lt;code&gt;[main]&lt;/code&gt; section name is the &lt;strong&gt;stanza name&lt;/strong&gt;; any name works. Use something that identifies
the cluster, because it is part of every command you run.&lt;/p&gt;
&lt;h2 id="step-4-configure-postgresql-to-archive-wal"&gt;Step 4: Configure PostgreSQL to Archive WAL
&lt;/h2&gt;&lt;p&gt;Add these to &lt;code&gt;postgresql.conf&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;archive_mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;on&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;archive_command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;pgbackrest --stanza=main archive-push %p&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;wal_level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;replica&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;max_wal_senders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;archive_mode = on&lt;/code&gt;: PostgreSQL calls &lt;code&gt;archive_command&lt;/code&gt; for every finished WAL segment.
&lt;strong&gt;Needs a restart&lt;/strong&gt;, not just a reload.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;archive_command&lt;/code&gt;: &lt;code&gt;%p&lt;/code&gt; is the path of the segment. PostgreSQL only recycles a segment
after this command exits 0, so a failing archive makes &lt;code&gt;pg_wal&lt;/code&gt; grow until it succeeds.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wal_level = replica&lt;/code&gt;: the minimum for archiving and physical backups. It is the default since
PostgreSQL 10; just don&amp;rsquo;t set it to &lt;code&gt;minimal&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;max_wal_senders&lt;/code&gt;: replication connections; only needed for standbys, harmless otherwise.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Optionally, force a segment switch on quiet databases so the archive is never more than a minute
behind:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;archive_timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;60&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;archive_timeout&lt;/code&gt; (seconds) caps your &lt;strong&gt;RPO&lt;/strong&gt;, the data you can lose, on a low-traffic server.
Each forced switch archives a full 16 MB segment, so don&amp;rsquo;t set it too low.&lt;/p&gt;
&lt;p&gt;Restart PostgreSQL:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl restart postgresql-17
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-5-create-the-stanza-and-check-it"&gt;Step 5: Create the Stanza and Check It
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;stanza-create&lt;/code&gt; initialises the stanza&amp;rsquo;s directories and metadata files in the repository:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main stanza-create
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;check&lt;/code&gt; proves the whole path works: it confirms the config, connects to PostgreSQL, forces a WAL
switch and waits for that segment to arrive in the repository.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main check
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If &lt;code&gt;check&lt;/code&gt; times out, read the PostgreSQL log: a failing &lt;code&gt;archive_command&lt;/code&gt; logs every error
there. The usual causes are a stanza name mismatch, permissions on the repository path, and
&lt;code&gt;archive_mode&lt;/code&gt; not taking effect because PostgreSQL was only reloaded.&lt;/p&gt;
&lt;h2 id="step-6-take-your-first-backups"&gt;Step 6: Take Your First Backups
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main --type&lt;span class="o"&gt;=&lt;/span&gt;full backup
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main --type&lt;span class="o"&gt;=&lt;/span&gt;diff backup
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main --type&lt;span class="o"&gt;=&lt;/span&gt;incr backup
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;--type&lt;/code&gt; takes &lt;code&gt;full&lt;/code&gt;, &lt;code&gt;diff&lt;/code&gt; or &lt;code&gt;incr&lt;/code&gt; (default &lt;code&gt;incr&lt;/code&gt;). If no full exists yet, pgBackRest
silently upgrades a &lt;code&gt;diff&lt;/code&gt; or &lt;code&gt;incr&lt;/code&gt; to a full: a fresh stanza never has an orphaned
incremental.&lt;/p&gt;
&lt;p&gt;Useful &lt;code&gt;backup&lt;/code&gt; options:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Option&lt;/th&gt;
					&lt;th&gt;Default&lt;/th&gt;
					&lt;th&gt;Meaning&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--type&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;incr&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;full&lt;/code&gt;, &lt;code&gt;diff&lt;/code&gt; or &lt;code&gt;incr&lt;/code&gt;.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--start-fast&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;n&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Force a checkpoint so the backup starts immediately.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--process-max&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Parallel processes for compression and transfer. The single biggest speed knob. Don&amp;rsquo;t starve the database: leave most cores for PostgreSQL.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--compress-type&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;gz&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;none&lt;/code&gt;, &lt;code&gt;bz2&lt;/code&gt;, &lt;code&gt;gz&lt;/code&gt;, &lt;code&gt;lz4&lt;/code&gt; or &lt;code&gt;zst&lt;/code&gt;. &lt;code&gt;zst&lt;/code&gt; is the best size/speed trade-off; &lt;code&gt;lz4&lt;/code&gt; is fastest.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--compress-level&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;per type&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;zst&lt;/code&gt; 3, &lt;code&gt;gz&lt;/code&gt; 6, &lt;code&gt;lz4&lt;/code&gt; 1, &lt;code&gt;bz2&lt;/code&gt; 9. Higher is smaller and slower.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--delta&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;n&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Decide which files changed by checksum instead of timestamp. Slower; use it if you can&amp;rsquo;t trust file timestamps.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--resume&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;y&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Resume a failed backup of the same type instead of starting over (see Step 13).&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--archive-check&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;y&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Wait until the WAL needed to make this backup consistent has been archived. Leave on.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--archive-copy&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;n&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Also copy that WAL into the backup itself, so it restores even if the WAL archive is lost.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--expire-auto&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;y&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Run &lt;code&gt;expire&lt;/code&gt; automatically after a successful backup.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--annotation&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;none&lt;/td&gt;
					&lt;td&gt;Attach &lt;code&gt;key=value&lt;/code&gt; metadata, e.g. &lt;code&gt;--annotation=reason=&amp;quot;before v2 migration&amp;quot;&lt;/code&gt;. Repeatable.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--repo&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;first repo&lt;/td&gt;
					&lt;td&gt;Which repository to back up to. With several repos you must pick one per run (Step 10).&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--exclude&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;none&lt;/td&gt;
					&lt;td&gt;Skip a path relative to the data directory. Use sparingly: whatever you exclude is missing from every restore.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="step-7-inspect-backups-with-info"&gt;Step 7: Inspect Backups with info
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;info&lt;/code&gt; is the main view. pgBackRest has no web UI; &lt;code&gt;info&lt;/code&gt;, the logs and your monitoring are the
interface.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main info
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;stanza: main
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; status: ok
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; cipher: none
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; db (current)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; wal archive min/max (17): 000000010000000000000003/00000001000000000000000B
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; full backup: 20261028-081210F
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; timestamp start/stop: 2026-10-28 08:12:10+00 / 2026-10-28 08:12:41+00
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; wal start/stop: 000000010000000000000004 / 000000010000000000000004
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; database size: 29.5MB, database backup size: 29.5MB
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; repo1: backup size: 3.9MB
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; diff backup: 20261028-081210F_20261028-081402D
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; timestamp start/stop: 2026-10-28 08:14:02+00 / 2026-10-28 08:14:05+00
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; wal start/stop: 000000010000000000000006 / 000000010000000000000006
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; database size: 29.5MB, database backup size: 8.3KB
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; repo1: backup size: 512B
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; backup reference total: 1 full
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;How to read it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;status&lt;/strong&gt;: &lt;code&gt;ok&lt;/code&gt;, or an error such as &lt;code&gt;no valid backups&lt;/code&gt; or &lt;code&gt;missing stanza path&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;wal archive min/max&lt;/strong&gt;: the oldest and newest WAL in the archive. You can restore to any point
between the first backup&amp;rsquo;s stop time and the max segment.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;database size&lt;/strong&gt;: the cluster&amp;rsquo;s size; &lt;strong&gt;database backup size&lt;/strong&gt;: what this backup had to copy.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;repo1: backup size&lt;/strong&gt;: the compressed size stored in the repo.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;backup reference&lt;/strong&gt;: what the backup depends on. A diff references its full.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Options:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Option&lt;/th&gt;
					&lt;th&gt;Meaning&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--output=json&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Machine-readable output, for monitoring (Step 16).&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--set=&amp;lt;label&amp;gt;&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Details of one backup, including its annotations and databases.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--repo=&amp;lt;n&amp;gt;&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Show only one repository.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="step-8-retention-and-expire"&gt;Step 8: Retention and Expire
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;expire&lt;/code&gt; deletes backups beyond your policy, and the WAL that only they needed. It runs after
every backup (&lt;code&gt;expire-auto=y&lt;/code&gt;), so you rarely run it by hand.&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Option&lt;/th&gt;
					&lt;th&gt;Default&lt;/th&gt;
					&lt;th&gt;Meaning&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;repo1-retention-full&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;none&lt;/td&gt;
					&lt;td&gt;Fulls to keep: a count, or days when the type is &lt;code&gt;time&lt;/code&gt;.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;repo1-retention-full-type&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;count&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;count&lt;/code&gt;: keep the newest N fulls. &lt;code&gt;time&lt;/code&gt;: keep fulls so that at least one is N days old.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;repo1-retention-diff&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;unset&lt;/td&gt;
					&lt;td&gt;Diffs to keep. Unset keeps every diff until its full expires. Fulls count as diffs here.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;repo1-retention-archive&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;derived&lt;/td&gt;
					&lt;td&gt;Backups&amp;rsquo; worth of continuous WAL to keep. Leave unset: WAL is then expired only with the backups that need it.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;repo1-retention-archive-type&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;full&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;full&lt;/code&gt;, &lt;code&gt;diff&lt;/code&gt; or &lt;code&gt;incr&lt;/code&gt;: what &lt;code&gt;retention-archive&lt;/code&gt; counts.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;repo1-retention-history&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;365&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Days of backup history manifests to keep.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Your PITR window runs from the oldest retained full to now. With weekly fulls and
&lt;code&gt;repo1-retention-full=4&lt;/code&gt; that&amp;rsquo;s about four weeks.&lt;/p&gt;
&lt;p&gt;Remove one specific backup, and everything that depends on it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main --set&lt;span class="o"&gt;=&lt;/span&gt;20261028-081210F_20261028-081402D expire
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Avoid setting &lt;code&gt;retention-archive&lt;/code&gt; aggressively to save space: PITR from a backup whose WAL was
expired is impossible.&lt;/p&gt;
&lt;h2 id="step-9-store-backups-in-s3-with-encryption"&gt;Step 9: Store Backups in S3 with Encryption
&lt;/h2&gt;&lt;p&gt;A repository on the database host doesn&amp;rsquo;t survive the host. Put it in object storage. pgBackRest
speaks the S3 API natively, so AWS S3, MinIO, Hetzner, Wasabi, Backblaze B2 and Cloudflare R2 all
work.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# /etc/pgbackrest/pgbackrest.conf&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[global]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo1-type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;s3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo1-path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/pgbackrest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo1-s3-bucket&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;my-pg-backups&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo1-s3-endpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;s3.eu-west-1.amazonaws.com&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo1-s3-region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;eu-west-1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo1-retention-full&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo1-cipher-type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;aes-256-cbc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo1-bundle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;y&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo1-block&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;y&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;process-max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;compress-type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;zst&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;start-fast&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;y&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;log-level-console&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;info&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;log-level-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;detail&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[main]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;pg1-path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/var/lib/pgsql/17/data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Keep the secrets in a separate file only &lt;code&gt;postgres&lt;/code&gt; can read:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# /etc/pgbackrest/conf.d/secrets.conf (chmod 0640, owner root:postgres)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[global]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo1-s3-key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;access key id&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo1-s3-key-secret&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;secret access key&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo1-cipher-pass&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;generated passphrase&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Generate the passphrase once:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;openssl rand -base64 &lt;span class="m"&gt;48&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Store the cipher passphrase outside the server&lt;/strong&gt;, in your secrets manager. Without it the
backups cannot be decrypted, by you or anyone else. That is the point of encryption, and also the
easiest way to lose every backup you have.&lt;/p&gt;
&lt;p&gt;The S3 and encryption options:&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Option&lt;/th&gt;
					&lt;th&gt;Meaning&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;repo1-type&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;posix&lt;/code&gt; (default, a local or mounted path), &lt;code&gt;s3&lt;/code&gt;, &lt;code&gt;azure&lt;/code&gt;, &lt;code&gt;gcs&lt;/code&gt;, &lt;code&gt;sftp&lt;/code&gt; or &lt;code&gt;cifs&lt;/code&gt;.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;repo1-s3-bucket&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;The bucket name.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;repo1-s3-endpoint&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;The S3 API host, e.g. &lt;code&gt;s3.eu-west-1.amazonaws.com&lt;/code&gt; or your provider&amp;rsquo;s endpoint.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;repo1-s3-region&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;The bucket&amp;rsquo;s region. Required even for providers that ignore it.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;repo1-s3-key&lt;/code&gt; / &lt;code&gt;repo1-s3-key-secret&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Access key pair, when &lt;code&gt;repo1-s3-key-type=shared&lt;/code&gt; (default).&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;repo1-s3-key-type&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;shared&lt;/code&gt; (keys in config), &lt;code&gt;auto&lt;/code&gt; (EC2 instance role), &lt;code&gt;web-id&lt;/code&gt; (EKS IRSA).&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;repo1-s3-uri-style&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;host&lt;/code&gt; (default, &lt;code&gt;bucket.endpoint&lt;/code&gt;) or &lt;code&gt;path&lt;/code&gt; (&lt;code&gt;endpoint/bucket&lt;/code&gt;). MinIO usually needs &lt;code&gt;path&lt;/code&gt;.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;repo1-storage-verify-tls&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Default &lt;code&gt;y&lt;/code&gt;. Set &lt;code&gt;n&lt;/code&gt; only for a test endpoint with a self-signed certificate.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;repo1-cipher-type&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;none&lt;/code&gt; or &lt;code&gt;aes-256-cbc&lt;/code&gt;. Encryption happens on the client before upload, so the storage provider never sees plaintext.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;repo1-cipher-pass&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;The passphrase. Cannot be changed after &lt;code&gt;stanza-create&lt;/code&gt; for that repo.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;repo1-bundle&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Pack small files into bundles: far fewer objects and requests on object storage. Needed for &lt;code&gt;repo1-block&lt;/code&gt;.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;repo1-block&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Block incremental: diffs and incrementals store changed &lt;strong&gt;blocks&lt;/strong&gt; of a file instead of the whole file. Large tables with small changes go from gigabytes per diff to megabytes. Most efficient when enabled from the first full.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;process-max&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;In &lt;code&gt;[global]&lt;/code&gt;, applies to every command: backup, restore, async archiving.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Then create the stanza on the new repo and check it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main stanza-create
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main check
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-10-multiple-repositories"&gt;Step 10: Multiple Repositories
&lt;/h2&gt;&lt;p&gt;One copy is not a backup strategy. pgBackRest supports up to 256 repositories per stanza: say a
nearby bucket for fast restores and a second region (or provider) for disasters.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[global]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo1-type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;s3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo1-path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/pgbackrest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo1-s3-bucket&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;pg-backups-primary&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo1-s3-endpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;s3.eu-west-1.amazonaws.com&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo1-s3-region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;eu-west-1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo1-retention-full&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo1-cipher-type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;aes-256-cbc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo1-bundle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;y&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo1-block&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;y&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo2-type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;s3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo2-path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/pgbackrest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo2-s3-bucket&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;pg-backups-dr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo2-s3-endpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;s3.eu-central-1.amazonaws.com&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo2-s3-region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;eu-central-1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo2-retention-full&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo2-cipher-type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;aes-256-cbc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo2-bundle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;y&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;repo2-block&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;y&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Each repo gets its own keys and its own cipher passphrase (&lt;code&gt;repo2-s3-key&lt;/code&gt;, &lt;code&gt;repo2-cipher-pass&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;How the commands treat several repos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;archive-push&lt;/code&gt; writes WAL to every repo.&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;backup&lt;/code&gt; writes to one repo&lt;/strong&gt;, &lt;code&gt;repo1&lt;/code&gt; unless you pass &lt;code&gt;--repo&lt;/code&gt;. To back up to both, run it
once per repo:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main --repo&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; --type&lt;span class="o"&gt;=&lt;/span&gt;full backup
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main --repo&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt; --type&lt;span class="o"&gt;=&lt;/span&gt;full backup
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This catches people out: with two repos and a plain &lt;code&gt;backup&lt;/code&gt;, repo2 only ever gets WAL, never a
base backup.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;restore&lt;/code&gt;&lt;/strong&gt; looks for a suitable backup in repo order unless you pass &lt;code&gt;--repo&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;info&lt;/code&gt;&lt;/strong&gt; shows every repo; &lt;code&gt;--repo&lt;/code&gt; narrows it.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="step-11-asynchronous-wal-archiving"&gt;Step 11: Asynchronous WAL Archiving
&lt;/h2&gt;&lt;p&gt;By default &lt;code&gt;archive-push&lt;/code&gt; is synchronous: PostgreSQL waits for each segment to upload before
archiving the next. On a busy server, or with remote object storage, that becomes a bottleneck
and &lt;code&gt;pg_wal&lt;/code&gt; grows. Asynchronous mode decouples the two:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[global]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;archive-async&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;y&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;spool-path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/var/spool/pgbackrest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;archive-push-queue-max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;50GiB&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[global:archive-push]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;process-max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;archive-timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;300&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[global:archive-get]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;process-max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Option&lt;/th&gt;
					&lt;th&gt;Default&lt;/th&gt;
					&lt;th&gt;Meaning&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;archive-async&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;n&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Push WAL from a background process in parallel batches; PostgreSQL gets a fast acknowledgement from the spool. For &lt;code&gt;archive-get&lt;/code&gt;, prefetch WAL during recovery.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;spool-path&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;/var/spool/pgbackrest&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Local directory for acknowledgements and prefetched WAL. Must be local disk, not NFS.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;archive-push-queue-max&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;unlimited&lt;/td&gt;
					&lt;td&gt;When this much un-archived WAL piles up (say the repo is down), pgBackRest tells PostgreSQL the WAL is archived and &lt;strong&gt;drops it&lt;/strong&gt;. This protects the database from a full disk, at the cost of a gap in PITR until the next backup. Size it to fit comfortably on the &lt;code&gt;pg_wal&lt;/code&gt; volume.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;archive-push-batch-size&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;16GiB&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Max WAL pushed per async run; lower values recheck the queue limit more often.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;archive-get-queue-max&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;128MiB&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;How much WAL &lt;code&gt;archive-get&lt;/code&gt; prefetches into the spool during recovery. Raise it to speed up long replays.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;archive-timeout&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;1m&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;How long &lt;code&gt;archive-push&lt;/code&gt;, &lt;code&gt;check&lt;/code&gt; and &lt;code&gt;backup&lt;/code&gt; wait for a WAL segment to reach the repo. With async mode and a slow repo, raise it.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;process-max&lt;/code&gt; (per command)&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Parallel uploads/downloads for archiving.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;archive-push-queue-max&lt;/code&gt; is the most important safety option here. Without it, an unreachable
repository fills &lt;code&gt;pg_wal&lt;/code&gt;, and when that volume is full &lt;strong&gt;PostgreSQL stops&lt;/strong&gt;. With it, you lose
PITR for a window, but the database stays up.&lt;/p&gt;
&lt;h2 id="step-12-schedule-backups-with-systemd-timers"&gt;Step 12: Schedule Backups with systemd Timers
&lt;/h2&gt;&lt;p&gt;A common schedule: weekly full, daily diff. Put the backup logic in one templated service:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# /etc/systemd/system/pgbackrest-backup@.service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[Unit]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;pgBackRest %i backup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;After&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;postgresql-17.service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[Service]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;oneshot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;User&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;postgres&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;Nice&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;IOSchedulingClass&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;best-effort&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;IOSchedulingPriority&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;7&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;ExecStart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/usr/bin/pgbackrest --stanza=main --repo=1 --type=%i backup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;ExecStart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/usr/bin/pgbackrest --stanza=main --repo=2 --type=%i backup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;%i&lt;/code&gt; is the instance name: &lt;code&gt;pgbackrest-backup@full&lt;/code&gt; passes &lt;code&gt;--type=full&lt;/code&gt;. &lt;code&gt;Nice&lt;/code&gt; and
&lt;code&gt;IOSchedulingClass&lt;/code&gt; make the backup give way to the database. A &lt;code&gt;oneshot&lt;/code&gt; unit runs its
&lt;code&gt;ExecStart&lt;/code&gt; lines in order and stops at the first failure. If you&amp;rsquo;d rather repo2 still runs when
repo1 fails, use a small wrapper script that loops over the repos.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# /etc/systemd/system/pgbackrest-backup-full.timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[Unit]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Weekly pgBackRest full backup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[Timer]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;OnCalendar&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Sun *-*-* 01:00:00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;Persistent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;Unit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;pgbackrest-backup@full.service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[Install]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;WantedBy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;timers.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# /etc/systemd/system/pgbackrest-backup-diff.timer&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[Unit]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Daily pgBackRest differential backup&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[Timer]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;OnCalendar&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Mon..Sat *-*-* 01:00:00&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;Persistent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;Unit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;pgbackrest-backup@diff.service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[Install]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;WantedBy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;timers.target&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl daemon-reload
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; --now pgbackrest-backup-full.timer pgbackrest-backup-diff.timer
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl list-timers &lt;span class="s1"&gt;&amp;#39;pgbackrest-*&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;Persistent=true&lt;/code&gt; runs a missed backup at boot if the server was off at the scheduled time.&lt;/p&gt;
&lt;p&gt;Only one backup per stanza runs at a time; pgBackRest holds a lock. If a full is still running
when the diff timer fires, the diff fails on the lock. That&amp;rsquo;s harmless, but plan the schedule so
a slow full can finish.&lt;/p&gt;
&lt;h2 id="step-13-resuming-failed-backups"&gt;Step 13: Resuming Failed Backups
&lt;/h2&gt;&lt;p&gt;With &lt;code&gt;resume=y&lt;/code&gt; (the default), a failed backup leaves a partial backup in the repo. The next
backup &lt;strong&gt;of the same type&lt;/strong&gt; checks the files already copied and continues instead of starting
over:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;WARN: resumable backup 20261024-224141F of same type exists -- invalid files will be removed then the backup will resume
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The condition matters. If a &lt;strong&gt;different&lt;/strong&gt; type runs first, say tonight&amp;rsquo;s scheduled diff after
last night&amp;rsquo;s failed full, the partial full is discarded:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;INFO: backup &amp;#39;20261024-224141F&amp;#39; cannot be resumed: resume only valid for full backup
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So if a long full fails, retry the full before the next diff runs, or the next attempt starts
from zero.&lt;/p&gt;
&lt;h2 id="step-14-restoring-a-backup"&gt;Step 14: Restoring a Backup
&lt;/h2&gt;&lt;p&gt;Practise restores on a &lt;strong&gt;separate host&lt;/strong&gt;. Never restore over a running production data
directory unless that server is already lost. The restore host needs the same PostgreSQL major
version, pgBackRest, the same &lt;code&gt;pgbackrest.conf&lt;/code&gt; and secrets, and enough disk.&lt;/p&gt;
&lt;h3 id="full-restore-to-the-latest-point"&gt;Full Restore to the Latest Point
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl stop postgresql-17
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main restore
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl start postgresql-17
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;By default the data directory must be empty. pgBackRest copies the latest backup, writes
&lt;code&gt;restore_command&lt;/code&gt; into &lt;code&gt;postgresql.auto.conf&lt;/code&gt;, and creates &lt;code&gt;recovery.signal&lt;/code&gt;. PostgreSQL then
replays all available WAL and opens for writes.&lt;/p&gt;
&lt;h3 id="delta-restore"&gt;Delta Restore
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main --delta restore
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;--delta&lt;/code&gt; keeps files in the existing data directory whose checksums match the backup and only
fetches the rest. Restoring a large cluster that is mostly intact (a failed upgrade, a deleted
table) becomes much faster. PostgreSQL must be stopped.&lt;/p&gt;
&lt;h3 id="restore-options-explained"&gt;Restore Options Explained
&lt;/h3&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Option&lt;/th&gt;
					&lt;th&gt;Default&lt;/th&gt;
					&lt;th&gt;Meaning&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--set&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;latest&lt;/td&gt;
					&lt;td&gt;Which backup to restore, by label.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--type&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;default&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Recovery target type: &lt;code&gt;default&lt;/code&gt; (replay to the end of the archive), &lt;code&gt;immediate&lt;/code&gt; (stop as soon as consistent), &lt;code&gt;time&lt;/code&gt;, &lt;code&gt;xid&lt;/code&gt;, &lt;code&gt;lsn&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt; (a &lt;code&gt;pg_create_restore_point&lt;/code&gt;), &lt;code&gt;standby&lt;/code&gt; (create a replica), &lt;code&gt;preserve&lt;/code&gt; (keep existing recovery settings), &lt;code&gt;none&lt;/code&gt; (no recovery settings).&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--target&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;none&lt;/td&gt;
					&lt;td&gt;The target for &lt;code&gt;time&lt;/code&gt;, &lt;code&gt;xid&lt;/code&gt;, &lt;code&gt;lsn&lt;/code&gt; or &lt;code&gt;name&lt;/code&gt;. A time is &lt;code&gt;&amp;quot;2026-10-28 09:59:00+00&amp;quot;&lt;/code&gt;.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--target-action&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;pause&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;What PostgreSQL does at the target: &lt;code&gt;pause&lt;/code&gt; (read-only, check the data, then &lt;code&gt;SELECT pg_wal_replay_resume()&lt;/code&gt;), &lt;code&gt;promote&lt;/code&gt; (open for writes), &lt;code&gt;shutdown&lt;/code&gt;.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--target-exclusive&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;n&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;With &lt;code&gt;y&lt;/code&gt;, stop just &lt;strong&gt;before&lt;/strong&gt; the target instead of just after it.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--target-timeline&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;latest&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Which timeline to follow after earlier promotions.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--delta&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;n&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Reuse files that match by checksum.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--force&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;n&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;With &lt;code&gt;--delta&lt;/code&gt;, overwrite a directory that doesn&amp;rsquo;t look like a PostgreSQL data directory.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--db-include&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;all&lt;/td&gt;
					&lt;td&gt;Restore only these databases (repeatable). Others are restored as empty sparse files and cannot be connected to.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--db-exclude&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;none&lt;/td&gt;
					&lt;td&gt;Restore everything except these databases.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--tablespace-map&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;original&lt;/td&gt;
					&lt;td&gt;Restore a tablespace elsewhere: &lt;code&gt;--tablespace-map=ts_01=/data/ts_01&lt;/code&gt;. &lt;code&gt;--tablespace-map-all&lt;/code&gt; moves them all.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--link-map&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;original&lt;/td&gt;
					&lt;td&gt;Change a symlink&amp;rsquo;s destination, e.g. a separate &lt;code&gt;pg_wal&lt;/code&gt; volume. &lt;code&gt;--link-all&lt;/code&gt; restores all links.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--archive-mode&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;preserve&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;off&lt;/code&gt; sets &lt;code&gt;archive_mode=off&lt;/code&gt; on the restored cluster. &lt;strong&gt;Always use &lt;code&gt;off&lt;/code&gt; on a scratch or test restore.&lt;/strong&gt; Otherwise the copy archives WAL into the production stanza.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--recovery-option&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;none&lt;/td&gt;
					&lt;td&gt;Add a recovery setting, e.g. &lt;code&gt;--recovery-option=primary_conninfo=...&lt;/code&gt;. Repeatable.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--repo&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;search in order&lt;/td&gt;
					&lt;td&gt;Restore from a specific repository.&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;--process-max&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
					&lt;td&gt;Parallel downloads and decompression. Restores are much faster with more.&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="step-15-point-in-time-recovery"&gt;Step 15: Point-in-Time Recovery
&lt;/h2&gt;&lt;p&gt;PITR is why you run pgBackRest. Someone dropped a table at 10:00:30; restore to 10:00:00.&lt;/p&gt;
&lt;p&gt;First find a backup that &lt;strong&gt;finished before&lt;/strong&gt; the target:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main info
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then restore with a time target:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl stop postgresql-17
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main --delta &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --set&lt;span class="o"&gt;=&lt;/span&gt;20261028-081210F &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --type&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;--target=2026-10-28 10:00:00+00&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --target-action&lt;span class="o"&gt;=&lt;/span&gt;pause &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --archive-mode&lt;span class="o"&gt;=&lt;/span&gt;off &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; restore
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl start postgresql-17
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With &lt;code&gt;--target-action=pause&lt;/code&gt;, PostgreSQL stops replaying at the target and stays read-only.
Check that the data is what you expect:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres psql -c &lt;span class="s2"&gt;&amp;#34;select count(*) from orders&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you need to go further, stop PostgreSQL and restore again with a later target. If it&amp;rsquo;s right,
open the database for writes:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres psql -c &lt;span class="s2"&gt;&amp;#34;select pg_wal_replay_resume()&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;PostgreSQL promotes onto a new &lt;strong&gt;timeline&lt;/strong&gt;. pgBackRest archives the new timeline&amp;rsquo;s WAL alongside
the old one, so you can still PITR across the promotion later.&lt;/p&gt;
&lt;p&gt;The most common PITR mistake is restoring a backup that finished &lt;strong&gt;after&lt;/strong&gt; the target. If &lt;code&gt;--set&lt;/code&gt;
is omitted, pgBackRest picks a backup before the target for you. If you pass a &lt;code&gt;--set&lt;/code&gt; that
finished after the target, PostgreSQL ignores the target and replays to the end of the archive,
which is exactly what you didn&amp;rsquo;t want. Always check the &lt;code&gt;timestamp start/stop&lt;/code&gt; line first.&lt;/p&gt;
&lt;h3 id="restoring-a-single-database"&gt;Restoring a Single Database
&lt;/h3&gt;&lt;p&gt;To recover one database without the rest of the cluster, restore with &lt;code&gt;--db-include&lt;/code&gt; on a scratch
host, then dump it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main --db-include&lt;span class="o"&gt;=&lt;/span&gt;shop &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --type&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;--target=2026-10-28 10:00:00+00&amp;#34;&lt;/span&gt; --target-action&lt;span class="o"&gt;=&lt;/span&gt;promote &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --archive-mode&lt;span class="o"&gt;=&lt;/span&gt;off restore
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo systemctl start postgresql-17
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pg_dump -Fc -d shop -f /tmp/shop.dump
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Load the dump into production with &lt;code&gt;pg_restore&lt;/code&gt;. You need disk for the included databases only,
because the excluded ones are restored as sparse zero-filled files.&lt;/p&gt;
&lt;h2 id="step-16-monitoring-pgbackrest"&gt;Step 16: Monitoring pgBackRest
&lt;/h2&gt;&lt;p&gt;A backup that silently stopped working is worse than none. Watch three things.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Backups are recent.&lt;/strong&gt; The JSON from &lt;code&gt;info&lt;/code&gt; gives each backup&amp;rsquo;s stop time:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main --output&lt;span class="o"&gt;=&lt;/span&gt;json info &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;|&lt;/span&gt; jq -r &lt;span class="s1"&gt;&amp;#39;.[0].backup[-1] | &amp;#34;\(.label) \(.type) \(.timestamp.stop)&amp;#34;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Alert when the newest backup is older than your schedule plus some slack, and separately when
the newest &lt;strong&gt;full&lt;/strong&gt; is older than a week and a bit. A run of successful diffs can hide a weekly
full that keeps failing.&lt;/p&gt;
&lt;p&gt;For Prometheus, one simple approach: have your backup wrapper write a textfile-collector metric on
success, e.g. &lt;code&gt;pgbackrest_last_success_timestamp_seconds{repo=&amp;quot;1&amp;quot;,type=&amp;quot;full&amp;quot;}&lt;/code&gt;, and alert on
&lt;code&gt;time() - metric&lt;/code&gt;. The textfile collector is part of the
&lt;a class="link" href="https://citizix.com/how-to-monitor-linux-servers-using-prometheus-node-exporter/" &gt;Prometheus node exporter&lt;/a&gt;. A
standalone exporter such as &lt;code&gt;pgbackrest_exporter&lt;/code&gt; reads &lt;code&gt;info&lt;/code&gt; for you instead.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. WAL is being archived.&lt;/strong&gt; PostgreSQL tracks archiving in &lt;code&gt;pg_stat_archiver&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres psql -c &lt;span class="s2"&gt;&amp;#34;select archived_count, last_archived_time, failed_count, last_failed_time from pg_stat_archiver&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;last_archived_time&lt;/code&gt; must keep moving. A rising &lt;code&gt;failed_count&lt;/code&gt; alone is normal, since PostgreSQL
retries failed segments. Archiving is broken when &lt;code&gt;last_archived_time&lt;/code&gt; stops advancing. With
postgres_exporter, &lt;code&gt;pg_stat_archiver_last_archive_age&lt;/code&gt; is the seconds since the last archived
segment: alert when it exceeds, say, 900 on a database that writes continuously.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. The stanza is healthy.&lt;/strong&gt; Run &lt;code&gt;check&lt;/code&gt; periodically; it exits non-zero if archiving to any repo
fails:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main check
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Logs for every command are in &lt;code&gt;/var/log/pgbackrest/main-&amp;lt;command&amp;gt;.log&lt;/code&gt;. When run under systemd,
the console output is also in &lt;code&gt;journalctl -u 'pgbackrest-backup@*'&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="step-17-verify-the-repository"&gt;Step 17: Verify the Repository
&lt;/h2&gt;&lt;p&gt;&lt;code&gt;verify&lt;/code&gt; reads the repository and checks every backup file and WAL segment against the checksums
recorded when they were written. It catches silent corruption in storage before you need the
backup:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main --repo&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; verify
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It reads the whole repository, so it costs bandwidth and, on object storage, request and egress
charges. Monthly is a reasonable cadence. &lt;code&gt;verify&lt;/code&gt; does not replace a &lt;strong&gt;restore test&lt;/strong&gt;: the only
proof a backup restores is restoring it. Schedule a real restore to a scratch host, time it, and
write the number down. That&amp;rsquo;s your RTO.&lt;/p&gt;
&lt;h2 id="step-18-day-two-operations"&gt;Step 18: Day-Two Operations
&lt;/h2&gt;&lt;h3 id="pause-pgbackrest-stop-and-start"&gt;Pause pgBackRest: stop and start
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;stop&lt;/code&gt; prevents new pgBackRest commands for a stanza (or all stanzas without &lt;code&gt;--stanza&lt;/code&gt;);
&lt;code&gt;--force&lt;/code&gt; also terminates running ones. Archiving fails while stopped, so WAL builds up in
&lt;code&gt;pg_wal&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main stop
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main start
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="after-a-postgresql-major-upgrade-stanza-upgrade"&gt;After a PostgreSQL Major Upgrade: stanza-upgrade
&lt;/h3&gt;&lt;p&gt;After &lt;code&gt;pg_upgrade&lt;/code&gt; (say 17 to 18), the system identifier and version change, and archiving fails
until the stanza is upgraded:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main stanza-upgrade
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main --type&lt;span class="o"&gt;=&lt;/span&gt;full backup
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Update &lt;code&gt;pg1-path&lt;/code&gt; to the new data directory first, and take a new full right away. Backups from
the old version stay in the repo, restorable to the old version only.&lt;/p&gt;
&lt;h3 id="annotate-backups"&gt;Annotate Backups
&lt;/h3&gt;&lt;p&gt;Add or change metadata on an existing backup. An empty value removes a key:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main --set&lt;span class="o"&gt;=&lt;/span&gt;20261028-081210F &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --annotation&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;reason&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;pre-migration&amp;#34;&lt;/span&gt; annotate
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main --set&lt;span class="o"&gt;=&lt;/span&gt;20261028-081210F info
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="browse-the-repository-repo-ls-and-repo-get"&gt;Browse the Repository: repo-ls and repo-get
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main --repo&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; repo-ls backup/main
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main --repo&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; repo-get backup/main/backup.info
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;repo-ls&lt;/code&gt; lists paths inside the repo (relative to &lt;code&gt;repo-path&lt;/code&gt;). &lt;code&gt;repo-get&lt;/code&gt; prints a file,
decrypting and decompressing it. Useful for confirming a partial backup exists, or what is
actually in a bucket, without touching S3 credentials yourself.&lt;/p&gt;
&lt;h3 id="remove-a-stanza-stanza-delete"&gt;Remove a Stanza: stanza-delete
&lt;/h3&gt;&lt;p&gt;Permanently deletes every backup and WAL of a stanza from a repository:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main stop
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main --repo&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; stanza-delete
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;PostgreSQL must be stopped or you need &lt;code&gt;--force&lt;/code&gt;. There is no undo.&lt;/p&gt;
&lt;h3 id="emergency-stop-archiving-without-a-restart"&gt;Emergency: Stop Archiving Without a Restart
&lt;/h3&gt;&lt;p&gt;If the repository is down for a long time and &lt;code&gt;pg_wal&lt;/code&gt; is about to fill, switch archiving to a
no-op and reload:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres psql -c &lt;span class="s2"&gt;&amp;#34;ALTER SYSTEM SET archive_command = &amp;#39;/bin/true&amp;#39;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres psql -c &lt;span class="s2"&gt;&amp;#34;SELECT pg_reload_conf()&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Never use an empty string.&lt;/strong&gt; With &lt;code&gt;archive_mode=on&lt;/code&gt;, an empty &lt;code&gt;archive_command&lt;/code&gt; means &amp;ldquo;keep
every segment&amp;rdquo;, and &lt;code&gt;pg_wal&lt;/code&gt; fills. When the repo is back, &lt;code&gt;ALTER SYSTEM RESET archive_command&lt;/code&gt;,
reload, and take a new full backup, since the WAL discarded in between is a PITR gap.&lt;/p&gt;
&lt;h2 id="advanced-topologies"&gt;Advanced Topologies
&lt;/h2&gt;&lt;h3 id="backup-from-a-standby"&gt;Backup from a Standby
&lt;/h3&gt;&lt;p&gt;To keep backup I/O off the primary, read the data files from a streaming replica:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;[main]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;pg1-path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/var/lib/pgsql/17/data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;pg2-host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;standby.example.com&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;pg2-path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/var/lib/pgsql/17/data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;backup-standby&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;y&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;backup-standby=y&lt;/code&gt; copies files from the standby, while the primary still handles
&lt;code&gt;pg_backup_start&lt;/code&gt; and &lt;code&gt;pg_backup_stop&lt;/code&gt; and archives WAL. &lt;code&gt;prefer&lt;/code&gt; falls back to the primary when
no standby is available. The standby is reached over SSH or pgBackRest&amp;rsquo;s TLS server, so both
hosts need pgBackRest installed and configured.&lt;/p&gt;
&lt;h3 id="dedicated-repository-host"&gt;Dedicated Repository Host
&lt;/h3&gt;&lt;p&gt;For fleets of databases, run pgBackRest on a separate &lt;strong&gt;repository host&lt;/strong&gt; that pulls backups from
every database server over SSH or TLS (&lt;code&gt;pgbackrest server&lt;/code&gt;, &lt;code&gt;repo1-host&lt;/code&gt;, &lt;code&gt;pg1-host&lt;/code&gt;). Database
hosts then never hold repository credentials. It&amp;rsquo;s more to run; for one or two databases, direct
object storage is simpler.&lt;/p&gt;
&lt;h3 id="create-a-standby-from-a-backup"&gt;Create a Standby from a Backup
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;--type=standby&lt;/code&gt; restores a backup as a streaming replica that starts in standby mode:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -u postgres pgbackrest --stanza&lt;span class="o"&gt;=&lt;/span&gt;main --type&lt;span class="o"&gt;=&lt;/span&gt;standby &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --recovery-option&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;primary_conninfo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;host=primary.example.com user=replicator&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; restore
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The new standby fetches missing WAL from the archive and then streams from the primary. Building a
replica from object storage doesn&amp;rsquo;t load the primary the way &lt;code&gt;pg_basebackup&lt;/code&gt; does.&lt;/p&gt;
&lt;h2 id="lessons-from-running-pgbackrest-in-production"&gt;Lessons from Running pgBackRest in Production
&lt;/h2&gt;&lt;p&gt;These come from running pgBackRest against a ~1 TB PostgreSQL cluster with two object-storage
repositories in different regions.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;archive_mode&lt;/code&gt; needs a restart.&lt;/strong&gt; We shipped the config and created the stanza, then waited
for a maintenance window to restart. For days every backup failed with
&lt;code&gt;archive_mode must be enabled&lt;/code&gt;. Alert on backup age from day one.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;backup&lt;/code&gt; only writes to &lt;code&gt;repo1&lt;/code&gt;&lt;/strong&gt; unless you pass &lt;code&gt;--repo&lt;/code&gt;. Loop over the repos.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Object storage has bad nights.&lt;/strong&gt; One region returned &lt;code&gt;504 Gateway Timeout&lt;/code&gt; and dropped
connections for 1–2 hours two Saturdays in a row, exactly when the weekly full was uploading.
A few short retries can&amp;rsquo;t outlast that. Retry for hours, not minutes, since resume keeps each
attempt&amp;rsquo;s progress.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A diff in between kills the resume of a failed full&lt;/strong&gt;, so retry the full first.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Raise &lt;code&gt;archive-timeout&lt;/code&gt; for slow repos.&lt;/strong&gt; At the 1-minute default, a small share of WAL pushes
to a slow region timed out and were retried. 300 seconds made the noise go away.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mind the network.&lt;/strong&gt; A full of 1 TB to two repos reads the database twice. With
&lt;code&gt;process-max=8&lt;/code&gt; it can saturate a 1 Gbps link that also carries application traffic. Schedule
fulls off-peak and give the backup a low priority with &lt;code&gt;Nice&lt;/code&gt; and &lt;code&gt;IOSchedulingClass&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Retention per repo can differ.&lt;/strong&gt; A short window in the fast repo and a longer one in the DR
repo costs little with block incremental.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="command-cheat-sheet"&gt;Command Cheat Sheet
&lt;/h2&gt;&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Task&lt;/th&gt;
					&lt;th&gt;Command&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;Create stanza&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;pgbackrest --stanza=main stanza-create&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Check archiving end to end&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;pgbackrest --stanza=main check&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Full backup to repo1&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;pgbackrest --stanza=main --repo=1 --type=full backup&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Differential backup&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;pgbackrest --stanza=main --type=diff backup&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;List backups&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;pgbackrest --stanza=main info&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;JSON for monitoring&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;pgbackrest --stanza=main --output=json info&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Restore latest&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;pgbackrest --stanza=main restore&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Delta restore&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;pgbackrest --stanza=main --delta restore&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;PITR&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;pgbackrest --stanza=main --type=time &amp;quot;--target=...&amp;quot; --target-action=pause restore&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;One database&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;pgbackrest --stanza=main --db-include=shop restore&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Expire one backup&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;pgbackrest --stanza=main --set=&amp;lt;label&amp;gt; expire&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Verify repository&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;pgbackrest --stanza=main --repo=1 verify&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;After major upgrade&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;pgbackrest --stanza=main stanza-upgrade&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Pause / resume&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;pgbackrest --stanza=main stop&lt;/code&gt; / &lt;code&gt;start&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Browse repo&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;pgbackrest --stanza=main repo-ls backup/main&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Built-in help&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;pgbackrest help backup&lt;/code&gt; / &lt;code&gt;pgbackrest help restore type&lt;/code&gt;&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Run all of them as &lt;code&gt;postgres&lt;/code&gt; (&lt;code&gt;sudo -u postgres ...&lt;/code&gt;). &lt;code&gt;pgbackrest help &amp;lt;command&amp;gt; &amp;lt;option&amp;gt;&lt;/code&gt; prints
the full documentation of any option for your installed version.&lt;/p&gt;
&lt;h2 id="related-content"&gt;Related Content
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://citizix.com/how-to-backup-and-restore-postgres-database/" &gt;How to Backup and Restore a Postgres Database&lt;/a&gt; (logical backups with &lt;code&gt;pg_dump&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://citizix.com/how-to-install-and-configure-postgres-17-on-rocky-alma-linux-9/" &gt;How to Install and Configure Postgres 17 on Rocky/Alma Linux 9&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://citizix.com/postgres-create-user-create-database-and-manage-access/" &gt;Postgres Permissions: Create, Update, Delete Database Users&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://citizix.com/how-to-install-and-configure-prometheus-on-a-linux-server/" &gt;How to Install and Configure Prometheus on a Linux Server&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;pgBackRest turns PostgreSQL backups from a nightly dump into continuous protection: weekly fulls,
small block-incremental diffs, every WAL segment archived to encrypted object storage in more than
one place, and restores to any second in the retention window. Set it up in this order: archiving
and &lt;code&gt;check&lt;/code&gt;, then backups, then retention and a second repository. Then add the parts people
skip: alerts on backup age and archiving, a periodic &lt;code&gt;verify&lt;/code&gt;, and a timed restore to a scratch
host. A backup you&amp;rsquo;ve never restored is a hope, not a plan.&lt;/p&gt;</description></item></channel></rss>