PostgreSQL Backups on RDS & Aurora: Verify or Lose Data
Backups are the operation every team postpones until the day it needs one. On Amazon RDS and Aurora, the cloud takes snapshots for you — but “the cloud does it” is not a recovery plan. Snapshots fail. Restores time out. Permissions get forgotten. If you have not actually restored a backup this quarter, you do not have a backup; you have a hope. Here is the playbook Houston teams running Postgres on RDS and Aurora should follow: automate the snapshot, verify the restore, and keep a logical backup as the escape hatch.
Know What You Are Backing Up
PostgreSQL itself does not have one backup button — it has three families of backup: physical file copies (what snapshots and WAL archiving use), logical dumps (pg_dump/pg_restore), and continuous archiving for point-in-time recovery. On RDS and Aurora you get physical snapshots and PITR automatically; what you must add is verification — and, for portability, a logical layer.
Snapshots Are the Base Layer — Make Them Deliberate
RDS and Aurora take automatic snapshots during a backup window you choose and keep them for a retention period you set. Manual snapshots are the tool for releases, migrations, and pre-upgrade checkpoints, because they do not expire with the retention policy. Treat them as release artifacts:
# RDS: confirm your backup window and retention
aws rds describe-db-instances \
--db-instance-identifier mydb \
--query "DBInstances[].{Retention:BackupRetentionPeriod,Window:PreferredBackupWindow}"
# RDS: manual snapshot before a release
aws rds create-db-snapshot \
--db-instance-identifier mydb \
--db-snapshot-identifier mydb-v2-release
# Aurora: same idea at the cluster level
aws rds create-db-cluster-snapshot \
--db-cluster-identifier mycluster \
--db-cluster-snapshot-identifier mycluster-v2-release
A 35-day retention plus a weekly manual snapshot before every release covers the common cases: accidental DELETE, a bad migration, a corrupt deploy. It does not cover a regional outage — that is what cross-region snapshot copies and logical backups are for.
Verify Restores on a Schedule, Not in a Crisis
This is the step most teams skip, and it is the one that matters. Restoring to a brand-new instance is a safe, zero-impact way to prove the backup is restorable. Do it monthly and automate the check. Database automation vendors make the same pitch every year — push maintenance work into scripts so humans handle only the exceptions — and restore testing is the highest-value script you can write. A cron job that restores the latest snapshot to a scratch instance, checks table counts, and pages on mismatch will pay for itself the first time a snapshot turns out to be corrupt. When you can restore, run a row-count check, and confirm the app can connect, you have a backup. Until then, you have a rumor.
# Restore the latest snapshot into a scratch instance
aws rds restore-db-instance-from-db-snapshot \
--db-instance-identifier mydb-restore-check \
--db-snapshot-identifier mydb-v2-release
-- After the instance is available, verify data integrity
SELECT pg_database_size(current_database()) AS db_size;
SELECT schemaname, count(*)
FROM pg_tables
GROUP BY schemaname
ORDER BY schemaname;
Keep a Logical Backup as the Escape Hatch
Physical snapshots are fast to restore but are tied to the platform and the region. pg_dump output is portable: it can move you across major versions, across regions, or off RDS entirely. It is also your defense if a snapshot is silently corrupt. Run a daily logical dump of the databases that matter and — yes — test that restore too:
# Logical backup (custom format, compressed)
pg_dump -h mydb.xxxx.us-east-1.rds.amazonaws.com \
-U app -Fc -d mydb > mydb-$(date +%F).dump
# Test the restore into a scratch database
pg_restore --dbname mydb_restore_check --jobs 4 mydb-$(date +%F).dump
Custom-format dumps restore in parallel with --jobs, which keeps large restores practical. On Aurora, pair this with Aurora cloning: clones are instant and let you test against a full copy of live data without touching production.
Backups Are Your Incident Response
When critical PostgreSQL vulnerabilities make the rounds — code-execution and SQL-injection flaws like those disclosed earlier this year — the fastest recovery path is often a known-good snapshot restored to a clean instance, not hours of forensics on a compromised one. That only works if the snapshot is recent, tested, and restorable. Patch quickly, but know your exit ramp before you need it.
The One-Page Checklist
Print this. It is the whole job:
- Automatic backups on, 35-day retention, sane backup window.
- Manual snapshot before every release and major upgrade.
- Monthly restore test to a scratch instance with row-count verification.
- Daily
pg_dumpof critical databases; weeklypg_restoretest. - Cross-region snapshot copy for the disaster-recovery scenario.
- Restore runbook written down, including who can trigger it at 2 a.m.
Backups on RDS and Aurora are cheap to configure and expensive to skip. The snapshot is automatic; the recovery plan is not. Verify the restore, keep the logical escape hatch, and the next incident — whether it is a bad migration or a CVE in the wild — becomes a maintenance event instead of a fire drill.
