Database backups before changes
Before you upgrade a database, change its config or move it, take a dump you know you can restore. It takes a minute or two for most small databases, and it's the one backup a disk snapshot can't replace.
Published . Covers PostgreSQL, MySQL 8.4, Redis and MongoDB with their standard command-line tools, on any Linux server.
- Why a dump, not just a snapshot
- PostgreSQL
- MySQL and MariaDB
- Redis
- MongoDB
- Where to keep the dumps
- Check that a dump restores
Why a dump, not just a snapshot
A disk snapshot of a running server can catch a database halfway through writing. It usually recovers, but "usually" isn't what you want before an upgrade. A dump made by the database's own tool is consistent by design, it's small enough to copy off the server, and you can restore it into a different version or a different machine.
Take one right before the change, even if you have nightly backups. Last night's backup doesn't have this morning's data.
PostgreSQL
Use the custom format. It's compressed by default, and pg_restore can restore all of it or pick out single tables. pg_dump takes a consistent snapshot and doesn't block other users while it runs.
sudo -u postgres pg_dump -Fc -f /var/backups/appdb-$(date +%F-%H%M).dump appdb
pg_dump only dumps one database. Roles (users and their passwords) and tablespaces belong to the whole cluster, so dump them separately with pg_dumpall, which needs a superuser:
sudo -u postgres pg_dumpall --globals-only -f /var/backups/pg-globals-$(date +%F-%H%M).sql
The globals file is plain SQL, restored with psql. Without it, restoring on a fresh server gives errors for every owner and grant that names a role that doesn't exist there yet.
MySQL and MariaDB
For InnoDB tables, --single-transaction dumps a consistent state of the database without blocking applications. Without it, mysqldump locks tables while it reads them.
mysqldump --single-transaction --quick --routines --events \
appdb > /var/backups/appdb-$(date +%F-%H%M).sql
- Only InnoDB tables come out consistent. MyISAM or MEMORY tables can still change during the dump.
- Don't run
ALTER TABLE,CREATE TABLE,DROP TABLE,RENAME TABLEorTRUNCATE TABLEwhile the dump runs. A consistent read isn't isolated from them, and the dump can come out wrong or fail. - Triggers are included by default. Stored routines and events aren't, which is why the command adds
--routinesand--events. - Naming one database, as here, leaves out
CREATE DATABASEandUSE, so you can load the file into any database name.--databasesor--all-databasesadd those statements, and the file then restores into the original names.
These options are from the MySQL 8.4 manual. If you run MariaDB, check its own mysqldump documentation.
Redis
With RDB persistence on, Redis writes its data to a single file, dump.rdb by default. The file is never modified once written: Redis writes a new one under a temporary name and renames it into place when it's complete. So copying it while Redis runs is safe. Ask for a fresh one first:
redis-cli LASTSAVE # unix time of the last successful save
redis-cli BGSAVE # start a new one in the background
redis-cli LASTSAVE # repeat until the number changes: that save succeeded
redis-cli CONFIG GET dir # where the file is
redis-cli CONFIG GET dbfilename
sudo cp -a /var/lib/redis/dump.rdb /var/backups/redis-$(date +%F-%H%M).rdb
Use the path that CONFIG GET dir printed; /var/lib/redis is only the usual location for Debian and Ubuntu packages. If Redis requires a password, redis-cli needs it too.
If you run AOF only (no RDB), the Redis 7 and later AOF is several files in the appenddirname directory, and copying them during a rewrite can give you a broken backup. The Redis docs describe turning off automatic rewrites with CONFIG SET auto-aof-rewrite-percentage 0 while you copy, then setting it back.
MongoDB
mongodump can write everything to one compressed archive file, which is easier to move and keep than a directory of BSON files:
mongodump --uri="mongodb://localhost:27017" --username=backupUser \
--authenticationDatabase=admin --gzip \
--archive=/var/backups/mongo-$(date +%F-%H%M).archive.gz
Leave out --password and mongodump asks for it, which keeps it out of your shell history and the process list. On a replica set, add --oplog for a dump that reflects a single moment in time; it can't be combined with --db. Sharded clusters need more care; follow MongoDB's sharded cluster backup tutorial.
Where to keep the dumps
- Not only on the same server. If the change breaks the disk or you rebuild the server, a dump in
/var/backupsgoes with it. Copy it off:scp your.server.example:/var/backups/appdb-2026-10-30-1400.dump . - Not anywhere public. Never put a dump in a web root or a public bucket. Dumps hold every row and often password hashes.
- Readable by root only.
sudo chmod 600the files and keep/var/backupsclosed to other users. - Check there's room. Run
df -hfirst. A dump that fills the disk can take the database down with it.
A dump is only a backup once you've restored it. A file that exists isn't proof. An empty dump, a dump of the wrong database, or one cut short by a full disk all look fine until you need them.
Check that a dump restores
Restore into a new, empty database, never over the live one:
# PostgreSQL: list the contents, then restore into a scratch database
pg_restore --list /var/backups/appdb-2026-10-30-1400.dump | head
sudo -u postgres createdb -T template0 appdb_restoretest
sudo -u postgres pg_restore -d appdb_restoretest /var/backups/appdb-2026-10-30-1400.dump
# MySQL: load into a scratch database
mysql -e "CREATE DATABASE appdb_restoretest"
mysql appdb_restoretest < /var/backups/appdb-2026-10-30-1400.sql
# MongoDB: a dry run prints the restore summary without importing anything
mongorestore --gzip --archive=/var/backups/mongo-2026-10-30-1400.archive.gz --dryRun --verbose
Then count rows in a couple of tables you know, compare with the live database, and drop the test database. For Redis, start a second instance on another port with a copy of the RDB file in its dir, and compare DBSIZE. If your database is listening on the internet while you do any of this, fix that first: see Postgres exposed to the internet.
Stenvakt's database guard looks at every database it finds. It flags databases exposed to the internet and risky settings, and gives you a Back up now button before you change anything. Fixes run in safe mode, and you see each one in a Preview first. It's a Mac app and isn't out yet: get early access.
Sources
- PostgreSQL docs: pg_dump
- PostgreSQL docs: pg_restore
- MySQL 8.4 Reference Manual: mysqldump
- Redis docs: persistence and backing up Redis data
- MongoDB Database Tools: mongodump