Database backup strategy: the 3-2-1 rule and testing restores
Keep three copies of your data on two kinds of storage with one copy offsite, choose dump or snapshot methods per database, and prove backups work by restoring them on a schedule.
Drafted with AI from official documentation. Scripts were run in a test environment and repository links verified. Awaiting a human check. Did it work for you? Last edited Outdated?
Replication and RAID protect you from a failed disk or server. They do not protect you from a bad deploy, an accidental DELETE, ransomware or a lost data center, because they faithfully copy the damage. Backups are separate, older copies you can go back to.
The 3-2-1 rule
- 3 copies of the data: the primary plus two backups.
- 2 different media or storage systems, so one failure type cannot destroy all copies (for example local disk on a backup server plus object storage or tape).
- 1 copy offsite, outside the building or cloud region where the database runs.
For ransomware resilience, make at least one copy offline or immutable (write-once object storage, a disconnected disk, tape), and encrypt backups. Many ransomware variants search for reachable backups and delete or encrypt them too.
Step 1: define what you need
- RPO (recovery point objective): how much data, measured in time, you can afford to lose. Nightly dumps mean up to 24 hours.
- RTO (recovery time objective): how long a restore may take before the business suffers. Large dumps can take hours to load.
- Retention: how far back you must be able to go, for example 14 daily, 8 weekly and 12 monthly copies. Legal requirements may set minimums or maximums.
Step 2: pick a method per database
- Logical dumps (
mongodump,pg_dump,mysqldump): portable and easy to restore selectively. MongoDB recommendsmongodumpfor small deployments; for a consistent dump of a replica set use--oplog. - Filesystem or block snapshots (LVM, ZFS, cloud volume snapshots): fast for large datasets, but they must be taken in a crash-consistent way the database supports, and they restore the whole instance.
- Continuous approaches (WAL or oplog archiving, managed point-in-time recovery): lowest RPO, more moving parts.
- Redis: copy the RDB file, which is safe while Redis runs, or pull a snapshot with
redis-cli --rdb. AOF directories need rewrites paused during the copy.
# MongoDB: one compressed archive per run
mongodump --host=127.0.0.1 --username=backup --authenticationDatabase=admin \
--config=/etc/mongodb-backup/mongodump.yaml --oplog --gzip \
--archive=/var/backups/mongodb/mongodb-$(date +%F).archive.gz
# Redis: copy the latest snapshot with a date in the name
cp "$(redis-cli CONFIG GET dir | tail -n 1)/dump.rdb" /var/backups/redis/dump-$(date +%F-%H%M).rdb
Step 3: get copies off the host
Push or pull each night’s backup to a second system, and from there to the offsite copy. Verify after every transfer that size and checksum match:
sha256sum mongodb-2026-01-15.archive.gz > mongodb-2026-01-15.archive.gz.sha256
rsync -a mongodb-2026-01-15.archive.gz* [email protected]:/srv/backups/db1/
ssh [email protected] 'cd /srv/backups/db1 && sha256sum -c mongodb-2026-01-15.archive.gz.sha256'
Prefer a design where the backup server pulls from the database host, or where the database host can write but not delete. Then an attacker on the database server cannot erase the history.
Step 4: test restores on a schedule
A backup is only proven when it has been restored. Automate a restore test at least monthly, and after any change to the backup job:
- Pick a recent backup at random, not always the newest.
- Restore it to an isolated test server, never into production. Double-check the target host in the command before you press Enter.
- Check that it worked: counts of documents or rows in key collections, a few known records, application smoke tests against the restored copy.
- Record how long it took and compare with your RTO.
- Delete the test copy afterwards if it contains personal data, and keep a log entry of the test result.
mongorestore --host=restore-test.example.com --username=admin --authenticationDatabase=admin \
--gzip --archive=/srv/backups/db1/mongodb-2026-01-15.archive.gz --oplogReplay
mongosh "mongodb://[email protected]/shop?authSource=admin" \
--eval 'db.orders.countDocuments()'
Step 5: monitor the backups themselves
- Alert when the newest backup is older than expected, when its size drops sharply, or when a job exits with an error.
- Watch free space on backup targets so retention does not silently stop.
- Keep the restore procedure written down next to the backups, including where encryption keys and passwords are stored. Keys that exist only on the lost server make the backup useless.
Deleting old backups
Rotation scripts delete data. Test the selection with a dry run that only prints, for example find /var/backups/mongodb -name 'mongodb-*.archive.gz' -mtime +14 -print, before adding -delete, and only delete after the newest backup has been verified.
Official documentation
Did this work for you?
No votes yet. Be the first.
If it did not work, the report form below tells the editors what went wrong.
See also
- 0200 PostgreSQL roles, privileges and default privileges Create login and group roles, grant access to databases, schemas and tables, and use ALTER DEFAULT PRIVILEGES so tables created later get… Intermediate · Step by step · Linux Article Roles & administration · Security & access 15 Oct 2026
- 0201 pg_hba.conf and PostgreSQL authentication methods pg_hba.conf decides who may connect from where and how they must prove who they are. Rules are checked top to bottom and… Intermediate · Explains an idea · Linux Article Install & connect · Security & access 15 Oct 2026
- 0209 Fix: FATAL: password authentication failed for user PostgreSQL reached the server and found a matching pg_hba.conf rule, but the password check failed. Usually a wrong password, a role without… Intermediate · Fixes an error · Any system Article Roles & administration · Security & access 15 Oct 2026
- 0210 Fix: FATAL: no pg_hba.conf entry for host The server received the connection but no pg_hba.conf rule matches this client address, user, database and SSL mode. Add or correct a… Intermediate · Fixes an error · Linux Article Install & connect · Security & access 15 Oct 2026
- 0214 MySQL users and privileges: CREATE USER, GRANT and authentication plugins A MySQL account is a user name plus the host it connects from. You create it with CREATE USER, give it rights… Beginner · Step by step · Linux Article Administration · Security & access 15 Oct 2026
- 0216 MySQL vs MariaDB: what actually differs MariaDB started as a fork of MySQL and still speaks the same client protocol, but GTIDs, JSON storage, authentication and tooling have… Intermediate · Explains an idea · Linux Article Choosing a database · MySQL & MariaDB 15 Oct 2026
History
Every saved edit is kept. The plot on the sleeve draws one line per edit. Open any edit to see exactly what changed.
- Dominik +4,863 chars