PgBackRest Restore Scenario
Rescuing a Dropped PostgreSQL Database: Two pgBackRest Paths to Success
That sinking feeling when a DROP DATABASE command slips through... we've all been there, or at least dreaded it. The good news is that with robust tools like PostgreSQL and pgBackRest, recovery is often very achievable. I recently put this to the test after "accidentally" dropping a database named NEWDB and wanted to share two distinct, successful methods I used to bring it back.
The Setup:
- A PostgreSQL cluster with several databases, including one I created called
NEWDB. - Data was added to
NEWDB. - A full backup was taken using pgBackRest while
NEWDBexisted. - Then, the fateful command:
DROP DATABASE "NEWDB";
The mission: Restore NEWDB without impacting the other live databases.
Method 1: The Classic & Controlled - Restore to Temporary, then pg_dump/pg_restore
This is a well-trodden and highly reliable path for surgically extracting specific data from a full backup. It offers maximum control and isolates the recovery process until the very end.
The Core Idea:
You restore the entire cluster from a backup (taken before the drop) to a completely separate, temporary location. From this temporary, running instance, you then use pg_dump to export just the database you need (NEWDB), and finally, pg_restore to load it into your live production cluster.
Key Steps to Success:
- Identify the "Golden" Backup: Use
pgbackrest --stanza=mydb infoto find the label of the backup set that was taken beforeNEWDBwas dropped. This backup containsNEWDB. - Prepare a Temporary Restore Zone: Create new, empty directories for the temporary instance's data directory and its WAL files (especially if your main setup uses a symlinked
pg_wal). Ensure thepostgresuser has ownership.# Example paths sudo mkdir -p /mnt/pg_temp_restore/data sudo mkdir -p /mnt/pg_temp_restore/wal # If using symlinked WALs sudo chown -R postgres:postgres /mnt/pg_temp_restore sudo chmod -R 700 /mnt/pg_temp_restore - Perform a Point-In-Time Restore (PITR) to the Temporary Zone:
This is crucial. You want to restore the state of the cluster just beforeNEWDBwas dropped.pgbackrest --stanza=mydb \ --pg1-path=/mnt/pg_temp_restore/data \ --set=[LABEL_OF_BACKUP_WITH_NEWDB] \ --type=time \ --target="[YYYY-MM-DD HH:MM:SS_JUST_BEFORE_NEWDB_DROP]" \ --target-action=promote \ restore(Replace bracketed placeholders with your actual values. If you use a symlinked
pg_walin your main setup, after the restore command completes and before starting the temporary instance, go into/mnt/pg_temp_restore/data, remove thepg_waldirectory pgBackRest created, and create a symlink namedpg_walpointing to/mnt/pg_temp_restore/wal). - Configure & Start the Temporary PostgreSQL Instance:
Edit thepostgresql.confin/mnt/pg_temp_restore/datato use a port different from your live cluster (e.g.,port = 5433). Then, start this temporary instance:pg_ctl -D /mnt/pg_temp_restore/data -o "-p 5433" -l /mnt/pg_temp_restore/logfile startCheck its logfile for successful startup and recovery.
NEWDBshould be present here! - Dump
NEWDBfrom the Temporary Instance:pg_dump -p 5433 -U postgres -Fc -f /tmp/NEWDB_rescue.dump NEWDB - Shutdown & Clean Up the Temporary Instance:
pg_ctl -D /mnt/pg_temp_restore/data -m fast stop sudo rm -rf /mnt/pg_temp_restore # Free up the temporary space - Restore
NEWDBinto Your Live Cluster:
First, connect to your live PostgreSQL cluster and create an empty placeholder for the database:
Then, from your server's command line, use-- In psql connected to your live cluster CREATE DATABASE "NEWDB";pg_restore:pg_restore -U postgres -d NEWDB -v /tmp/NEWDB_rescue.dump rm /tmp/NEWDB_rescue.dump # Clean up the dump file
Why this method shines:
- Safety: Your live cluster isn't touched directly until the final, controlled
pg_restorestep. - Predictability: You know exactly what you're getting by isolating the restore.
- Universality: Works regardless of special backup flags or specific PostgreSQL/pgBackRest versions.
Method 2: The In-Place PITR with --delta - A Surprising Shortcut
Sometimes, a more direct approach can work, especially when the scope of the "damage" (the dropped database) is well understood and you have a precise target time. In my experiments, this method also successfully brought NEWDB back.
The Core Idea:
Use pgBackRest to perform a Point-In-Time Recovery (PITR) directly onto your existing data directory using the --delta flag. The --delta flag tells pgBackRest to update the target directory rather than requiring it to be empty. The magic lies in setting a PITR target time before the database drop was committed to the WALs.
Key Steps to Success:
- Identify a Suitable Backup and Target Time: pgBackRest will choose the latest backup that can satisfy the PITR target. You need to specify a
--targettimestamp that is just beforeNEWDBwas dropped.# Example: If NEWDB was dropped around 2025-05-31 20:35:00 # Target time could be "2025-05-31 20:32:00" as in my successful test - Perform the Delta PITR Restore:
(Ensure your live PostgreSQL cluster is stopped before running this if it directly modifies the primary PGDATA).pgbackrest --stanza=mydb \ --log-level-console=info \ --type=time \ --target="[YYYY-MM-DD HH:MM:SS_JUST_BEFORE_NEWDB_DROP]" \ restore --delta- pgBackRest will compare your live
/pgdata/mydb/data(whereNEWDB's files are now missing) with the chosen backup (whereNEWDB's files exist). - It will copy the "missing" files for
NEWDBback into your live data directory. - It will also set up
postgresql.auto.conffor PITR to your specified--targettime.
- pgBackRest will compare your live
- Handle Symlinked
pg_wal(If Applicable):
The restore might replace yourpg_walsymlink with a real directory. Before starting PostgreSQL,cdinto your data directory,sudo rm -rf pg_wal, and recreate your symlink:sudo ln -s /your/custom/wal_location/pg_wal pg_wal. - Start PostgreSQL & Promote:
Start your PostgreSQL server. It will enter recovery mode.
Connect viasudo systemctl start postgresql-17 # Or your service namepsqland monitor recovery:SELECT pg_is_in_recovery(); -- Once logs indicate it has reached the target or is ready: SELECT pg_promote(); - Verify:
NEWDBshould now be back in your\llist!
Why this method can work (and did for me):
- The
--deltarestore put the physical files forNEWDBback. - The precise
--targettime for PITR ensured that the WAL replay stopped before replaying theDROP DATABASE "NEWDB";command.
Important Note on the Delta Method:
While this worked in my controlled experiment, it's a more "expert" maneuver. It directly modifies your live data directory. Success hinges on a very accurate target time and a clear understanding of the state of your live data versus the backup. For critical production data, the isolation of Method 1 often provides greater peace of mind.
Conclusion:
pgBackRest, combined with PostgreSQL's robust Point-In-Time Recovery, offers powerful ways to recover from data loss. Whether you choose the meticulous control of a temporary restore and pg_dump, or a carefully targeted in-place delta PITR, the key is understanding your tools, your backups, and the timeline of events.
And remember, no matter how good your recovery tools are, nothing beats regularly testing your restore procedures!
Comments
Post a Comment