Knowing how to back up a MongoDB database is easy. Knowing that your backup actually restores, under pressure, at 3 a.m., on a 400 GB collection, is a different story. This guide covers the three realistic backup paths we use with clients at coding4.net, and more importantly, how to prove they work before you need them.
The short answer
For a quick, manual backup of a single MongoDB database, run:
mongodump --uri="mongodb://user:password@localhost:27017/?authSource=admin" --db=myapp --gzip --archive=/backups/myapp-2026-10-10.archive.gz
And to restore it:
mongorestore --uri="mongodb://user:password@localhost:27017/?authSource=admin" --gzip --archive=/backups/myapp-2026-10-10.archive.gz --drop
That is the 30 second version. Now let’s talk about doing it properly, because a single ad-hoc dump sitting on the same server as the database is not a backup strategy.
Which backup method should you use?
There are three paths that make sense in production. Pick based on data size and where MongoDB is hosted. For the wider picture, see How to Back Up MongoDB Databases.
| Method | Best for | Typical RPO | Main limitation |
|---|---|---|---|
| mongodump / mongorestore | Datasets under roughly 100 GB, dev and staging refreshes, single collection exports | Hours (whenever you last ran it) | Slow on large data, reads through the working set, no point-in-time recovery on its own |
| Scheduled cron script to S3 | Self-hosted replica sets, VPS, Docker, Kubernetes CronJobs | 15 minutes to 24 hours depending on schedule | You own the monitoring, retention and encryption |
| Atlas Cloud Backup snapshots | Anything running on MongoDB Atlas, especially multi-terabyte clusters | Seconds to minutes with continuous point-in-time restore | Not available on free M0 clusters, storage billed separately |
| Filesystem / EBS / LVM snapshots | Self-hosted clusters above a few hundred GB | Minutes | Journal and data files must be on the same volume, restores are all-or-nothing |
| Percona Backup for MongoDB / Ops Manager | Sharded clusters needing consistent point-in-time backups on-prem | Seconds to minutes | Extra component to install, configure and monitor |
Rule of thumb: if a full mongodump takes longer than your maintenance window, you have outgrown it. Move to snapshots and keep mongodump for logical exports and partial restores.

Before you start: tools and a dedicated backup user
1. Install the MongoDB Database Tools
Since MongoDB 4.4, mongodump, mongorestore, mongoexport and mongoimport ship in a separate package called MongoDB Database Tools. They are not installed with the server anymore.
# Debian / Ubuntu
sudo apt-get install -y mongodb-database-tools
# RHEL / Rocky / Alma
sudo dnf install -y mongodb-database-tools
# macOS
brew install mongodb/brew/mongodb-database-tools
# verify
mongodump --version
Keep the tools version equal to or newer than your server version. Running a 100.x tool against MongoDB 7.x or 8.x is fine, the reverse is not.
2. Create a least-privilege backup user
Never back up with your application user or with root. Create a dedicated account with the built-in backup role:
use admin
db.createUser({
user: "backup_user",
pwd: passwordPrompt(),
roles: [ { role: "backup", db: "admin" } ]
})
For the restore side, on the target instance only, use the restore role. Keeping them separate means a leaked backup credential cannot overwrite production.
Method 1: manual backups with mongodump and mongorestore
Backing up the whole server
mongodump \
--uri="mongodb://backup_user:PASSWORD@localhost:27017/?authSource=admin" \
--out=/var/backups/mongo/2026-10-10
This creates one folder per database, containing a .bson file and a .metadata.json file per collection. Index definitions are included, index data is not (indexes are rebuilt on restore).
Backing up a single database or collection
# one database
mongodump --uri="..." --db=shop --out=/var/backups/mongo
# one collection
mongodump --uri="..." --db=shop --collection=orders --out=/var/backups/mongo
# everything except noisy collections
mongodump --uri="..." --db=shop --excludeCollection=sessions --excludeCollection=logs --out=/var/backups/mongo
# only part of a collection
mongodump --uri="..." --db=shop --collection=orders \
--query='{"createdAt": {"$gte": {"$date": "2026-01-01T00:00:00Z"}}}' \
--out=/var/backups/mongo
Use archive and gzip, always
A single compressed archive file is far easier to move, checksum and upload than thousands of BSON files:
mongodump --uri="..." --gzip --archive=/var/backups/mongo/full-2026-10-10.archive.gz
You can even stream a dump straight into another cluster without touching disk:
mongodump --uri="mongodb://backup_user:PASS@prod-host:27017/?authSource=admin" --archive \
| mongorestore --uri="mongodb://restore_user:PASS@staging-host:27017/?authSource=admin" --archive --drop
Point-in-time consistency with –oplog
A plain mongodump is not a point-in-time snapshot. Collections are read one after another, so writes that happen during the dump produce an inconsistent picture. On a replica set, add --oplog:
mongodump --uri="..." --oplog --gzip --archive=/var/backups/mongo/full-2026-10-10.archive.gz
This captures the oplog entries written during the dump so the restore can replay them and land on a single consistent moment. Two constraints worth remembering:
--oplogonly works when dumping the full instance, not with--dbor--collection.- It is not supported on sharded clusters. For sharded deployments use Atlas, Ops Manager or Percona Backup for MongoDB.
Restoring
# restore an archive, dropping existing collections first
mongorestore --uri="..." --gzip --archive=/var/backups/mongo/full-2026-10-10.archive.gz --drop
# restore with oplog replay for point-in-time consistency
mongorestore --uri="..." --gzip --archive=/var/backups/mongo/full-2026-10-10.archive.gz --oplogReplay --drop
# restore a directory dump
mongorestore --uri="..." --dir=/var/backups/mongo/2026-10-10 --drop
# restore one database into a different name (great for restore drills)
mongorestore --uri="..." --gzip --archive=full.archive.gz \
--nsFrom='shop.*' --nsTo='shop_restoretest.*'
# validate the archive without writing anything
mongorestore --uri="..." --gzip --archive=full.archive.gz --dryRun -v
mongorestore flags that matter
--drop: drops each collection before restoring it. Without it, you merge into existing data, which is how people silently create duplicates.--dryRun: parses the archive and reports what would be restored. Cheap sanity check for a corrupted upload.--noIndexRestore: skip index builds, then create them manually in the background. Useful when restoring huge collections under time pressure.--numInsertionWorkersPerCollection=4: speeds up restores of a few very large collections.--numParallelCollections=4: restores several collections concurrently.--preserveUUID: keeps collection UUIDs, required in some replica set edge cases (needs--drop).

Method 2: automated cron backups pushed to S3
Manual dumps are fine until the one week nobody runs them. Automate it. Here is a production-shaped script we deploy regularly.
The script
#!/usr/bin/env bash
# /usr/local/bin/mongo-backup.sh
set -euo pipefail
# Secrets live in a root-only env file: chmod 600 /etc/mongo-backup.env
set -a
source /etc/mongo-backup.env # provides MONGO_PWD, S3_BUCKET, HEARTBEAT_URL
set +a
BACKUP_DIR=/var/backups/mongo
RETENTION_DAYS=7
STAMP=$(date -u +%Y%m%dT%H%M%SZ)
ARCHIVE="${BACKUP_DIR}/mongo-${STAMP}.archive.gz"
MONGO_URI="mongodb://backup_user:${MONGO_PWD}@10.0.1.21:27017,10.0.1.22:27017/?authSource=admin&replicaSet=rs0&readPreference=secondary"
mkdir -p "$BACKUP_DIR"
# 1. Dump from a secondary, with oplog, nice-d so production keeps its IO
ionice -c2 -n7 nice -n 10 mongodump \
--uri="$MONGO_URI" \
--oplog \
--gzip \
--numParallelCollections=2 \
--archive="$ARCHIVE"
# 2. Fail loudly on an empty or tiny archive
SIZE=$(stat -c%s "$ARCHIVE")
if [ "$SIZE" -lt 1048576 ]; then
echo "Backup suspiciously small: ${SIZE} bytes" >&2
exit 1
fi
# 3. Checksum so you can detect bit rot later
sha256sum "$ARCHIVE" > "${ARCHIVE}.sha256"
# 4. Ship it off the box
aws s3 cp "$ARCHIVE" "${S3_BUCKET}/daily/" --storage-class STANDARD_IA --only-show-errors
aws s3 cp "${ARCHIVE}.sha256" "${S3_BUCKET}/daily/" --only-show-errors
# 5. Local retention (S3 retention is handled by a lifecycle rule)
find "$BACKUP_DIR" -name 'mongo-*.archive.gz*' -mtime +${RETENTION_DAYS} -delete
# 6. Tell your monitoring the job finished
curl -fsS -m 10 --retry 3 "$HEARTBEAT_URL" > /dev/null
echo "Backup OK: $(basename "$ARCHIVE") (${SIZE} bytes)"
The crontab entry
sudo chmod 750 /usr/local/bin/mongo-backup.sh
sudo crontab -e
# Nightly full backup at 02:17 UTC (odd minutes avoid the global cron stampede)
17 2 * * * /usr/local/bin/mongo-backup.sh >> /var/log/mongo-backup.log 2>&1
On systemd hosts, a timer is nicer than cron because you get systemctl status, journald logs and OnFailure= hooks. On Kubernetes, the same script runs fine in a CronJob using the mongodb-database-tools image.
Non-negotiable rules for automated backups
- Off-host storage. A backup on the same server as the database dies with the server. S3, Backblaze B2, Wasabi, anything but local disk only.
- Versioning and object lock. Enable S3 versioning plus Object Lock in compliance mode. Ransomware deletes backups first, and a leaked IAM key should not be able to wipe your history.
- Lifecycle rules for retention. A typical grandfather-father-son setup: 7 daily, 4 weekly, 12 monthly, then transition to Glacier Instant Retrieval.
- Encryption. SSE-KMS on the bucket at minimum. For extra safety pipe through
ageorgpgbefore upload so the archive is useless even if the bucket leaks. - Dead man’s switch. Monitor the absence of a backup, not just failures. A cron job that never runs sends no error email. Healthchecks.io, Cronitor, or a simple Prometheus Pushgateway metric with an alert on staleness.
- Least-privilege IAM. The backup role should have
s3:PutObjectonly, nos3:DeleteObject.
Method 3: MongoDB Atlas snapshots and point-in-time restore
If you are on Atlas, most of the work above is already done for you, but you still need to configure it deliberately.
What you get per tier
- Free (M0) clusters: no automated snapshots. Your only option is
mongodumpon a schedule from outside Atlas, exactly like Method 2, pointed at yourmongodb+srv://connection string. - Flex clusters: daily snapshots with a short retention window, restorable from the UI.
- Dedicated clusters (M10 and above): full Cloud Backup with configurable snapshot policies, cross-region and cross-cloud snapshot copies, and continuous point-in-time restore down to the second within your oplog retention window.
Configuring a sane snapshot policy
- Open your cluster, go to Backup, then Edit Policy.
- Enable Cloud Backup and, on dedicated tiers, Continuous Cloud Backup (this is what gives you point-in-time recovery, not just daily snapshots).
- Set the snapshot cadence. A common policy: hourly snapshots kept 2 days, daily kept 7 days, weekly kept 4 weeks, monthly kept 12 months.
- Set the snapshot window outside your peak traffic hours.
- Enable snapshot distribution to a second region. A region outage should not also be a backup outage.
- Turn on backup compliance policy if you need immutable, undeletable backups for audit purposes. Note that it is deliberately hard to disable once enabled.
Restoring an Atlas snapshot
Three restore targets are available from Backup > Restore:
- Restore to a cluster: pick a snapshot or an exact point in time, then target the same cluster or, far better during an incident, a new temporary cluster. Restoring into a fresh cluster lets you inspect data before you cut traffic over.
- Download the snapshot: Atlas builds a downloadable archive you can restore locally with
mongorestore. Useful for compliance copies and for local debugging. - Automated restore via API or CLI.
# Atlas CLI examples
atlas backups snapshots list --clusterName prod-cluster --projectId <PROJECT_ID>
atlas backups snapshots create --clusterName prod-cluster \
--desc "pre-migration-2026-10-10" --retention 30
atlas backups restores start automated \
--clusterName prod-cluster \
--snapshotId <SNAPSHOT_ID> \
--targetClusterName restore-drill \
--targetProjectId <PROJECT_ID>
Always take a manual on-demand snapshot before a schema migration or a bulk update script. It costs a few cents and it is the difference between a five minute rollback and a very long evening.

Handling large collections without hurting production
mongodump does not take a global lock, so it will not block writes. What it does do is read every document through the WiredTiger cache, which evicts your hot working set and spikes disk IO. On a busy primary with a 300 GB dataset, that is felt by users.
Practical mitigations
- Dump from a secondary, never the primary. Add
readPreference=secondaryto the connection string, or better, point the backup directly at a hidden, non-voting member with priority 0. A hidden member never serves application reads, so cache pollution is harmless. - Throttle the process.
nice -n 10plusionice -c2 -n7, or a systemd slice withIOWriteBandwidthMax, keeps the dump from monopolising the disk. - Lower the parallelism. The default
--numParallelCollections=4is aggressive. Set it to 1 or 2 on constrained hosts. - Compress at the source.
--gziptrades a little CPU for far less disk write and network transfer. - Exclude what you can rebuild. Sessions, caches, job queues and raw log collections rarely need to be in a backup.
- Split very large collections. Dump cold historical data once with a
--queryrange filter, then only dump recent ranges nightly. - Watch the oplog window. If a backup takes longer than your oplog retention,
--oplogreplay can fail and secondaries can fall off the replica set. Check withrs.printReplicationInfo()and size the oplog for at least 2x your longest backup. - Above roughly 100 GB, stop dumping. Switch to volume snapshots (EBS, LVM, ZFS) or Percona Backup for MongoDB. Snapshot time is proportional to nothing, restore time is a volume attach instead of a multi-hour index rebuild.
Filesystem snapshot checklist (self-hosted)
- Data files and journal must be on the same logical volume, otherwise the snapshot is not recoverable.
- Snapshot a secondary, not the primary.
- If journaling is disabled or files span volumes, run
db.fsyncLock()before anddb.fsyncUnlock()after. Never do that on the primary. - On encrypted storage engines, snapshot the volume rather than copying files, so the keys stay consistent.
- For sharded clusters, stop the balancer first with
sh.stopBalancer()and snapshot all shards plus the config servers at the same time.
Test your restore before you need it
This is the part everybody skips and the only part that actually matters. An untested backup is a hypothesis, not a backup. Common ways backups silently fail: the cron job stopped after a server rebuild, the S3 key rotated, the archive is truncated, the dump only ever contained an empty database because of a wrong --db flag. Back up and restore MongoDB is a useful companion to this.
A restore drill you can run monthly in 10 minutes
#!/usr/bin/env bash
# restore-drill.sh - restore last night's backup into a throwaway container
set -euo pipefail
LATEST=$(aws s3 ls s3://acme-db-backups/mongodb/daily/ | grep '.archive.gz$' | sort | tail -n 1 | awk '{print $4}')
aws s3 cp "s3://acme-db-backups/mongodb/daily/${LATEST}" /tmp/
aws s3 cp "s3://acme-db-backups/mongodb/daily/${LATEST}.sha256" /tmp/
cd /tmp && sha256sum -c "${LATEST}.sha256"
docker run -d --name restore-drill -p 27018:27017 mongo:8
sleep 8
time mongorestore --uri="mongodb://localhost:27018" --gzip --archive="/tmp/${LATEST}" --drop
mongosh "mongodb://localhost:27018" --quiet --eval '
db.getMongo().getDBNames().forEach(function(n){
if (["admin","local","config"].indexOf(n) >= 0) return;
var d = db.getSiblingDB(n);
d.getCollectionNames().forEach(function(c){
print(n + "." + c + " = " + d.getCollection(c).countDocuments({}));
});
});
'
docker rm -f restore-drill
rm -f "/tmp/${LATEST}" "/tmp/${LATEST}.sha256"
What to verify, and what to write down
- Document counts per collection compared against production (allow for drift since the dump).
- Index presence: run
db.collection.getIndexes()and compare. A missing compound index turns a working restore into an outage. - Spot-check real documents, especially ones with dates, Decimal128 fields and binary data.
- Users and roles: they live in
admin.system.users. A per-database dump does not include them. Back up theadmindatabase too. - Measured restore time. This is your actual RTO. If management thinks it is 15 minutes and the drill says 3 hours, you have found something more valuable than the backup itself.
- A runbook: exact commands, credentials location, who to call, where DNS or connection strings need to change. Written before the incident, not during.
Put the drill in the calendar quarterly at minimum, monthly if the data is critical. Automate it in CI if you can, with the document count check as a pass/fail gate.

Common mistakes we see in audits
- Backups stored on the same host or the same cloud account as the database.
- Using
mongoexportfor backups. JSON export is not a backup: it loses BSON types such as Decimal128, precise dates and binary fields. Use it for data interchange, not recovery. - No backup of the
admindatabase, so users and roles vanish on restore. --oplogforgotten on a busy replica set, producing an inconsistent dump nobody notices until it is restored.- Retention set to a few days, so a corruption discovered three weeks later is already in every available copy.
- Credentials hardcoded in the crontab line, visible to anyone who can run
ps. - No alert on backup absence.
A sensible default setup
If you want a starting point that covers most small and mid-size production workloads:
- Run a three-node replica set with one hidden member reserved for backups.
- Nightly
mongodump --oplog --gzip --archivefrom the hidden member, uploaded to object storage with versioning and object lock. - Volume snapshots every 6 hours for fast whole-cluster recovery, or Atlas Continuous Cloud Backup if you are managed.
- Retention: 7 daily, 4 weekly, 12 monthly, with lifecycle transitions to cold storage.
- Heartbeat monitoring on every backup job, alerting if no success ping within 26 hours.
- Monthly automated restore drill with document count validation.
- A one-page runbook stored outside the systems it describes.
That combination gives you a low RPO from snapshots, a portable logical copy from mongodump for partial restores, and the evidence that both actually work.
FAQ
What is the MongoDB backup command?
The standard command is mongodump, part of the MongoDB Database Tools package. A full example: mongodump --uri="mongodb://user:pass@host:27017/?authSource=admin" --gzip --archive=/backups/db.archive.gz. The matching restore command is mongorestore.
Does mongodump lock the database?
No, mongodump does not take a global write lock. It does compete for disk IO and pollutes the WiredTiger cache, which can slow down production. Run it against a secondary or a hidden replica set member to avoid the impact.
How do I back up a MongoDB database from Compass?
MongoDB Compass has no true backup feature. It can export a collection to JSON or CSV from the collection view, which is useful for inspection but loses BSON type fidelity. For real backups use mongodump or Atlas snapshots, and use Compass only to verify data after a restore.
How do I restore a MongoDB dump?
For a directory dump: mongorestore --uri="..." --dir=/backups/dump --drop. For an archive: mongorestore --uri="..." --gzip --archive=/backups/db.archive.gz --drop. Add --oplogReplay if the dump was taken with --oplog, and --dryRun first if you want to validate the file without writing.
How do I back up only one collection?
mongodump --uri="..." --db=myapp --collection=orders --gzip --archive=/backups/orders.archive.gz. To restore it elsewhere under a different name, use --nsFrom and --nsTo with mongorestore.
How often should I back up MongoDB?
It depends on how much data you can afford to lose (your RPO). Nightly full dumps plus continuous point-in-time recovery is the common production baseline. For low-change internal systems, daily is usually enough. For transactional or financial data, you want point-in-time recovery measured in seconds, which means Atlas Continuous Cloud Backup, Ops Manager or Percona Backup for MongoDB. geeksforgeeks.org goes into the numbers.
Can I back up a MongoDB Atlas free cluster?
Free M0 clusters have no automated snapshots. Use mongodump against the cluster’s mongodb+srv:// connection string on a schedule, and store the archive off-platform. Upgrading to a paid tier is the only way to get managed snapshots and point-in-time restore.
Is mongodump suitable for very large databases?
Not really. Past roughly 100 GB, dump and especially restore times become painful because every index has to be rebuilt from scratch. Use filesystem or cloud volume snapshots, Atlas Cloud Backup, or Percona Backup for MongoDB, and keep mongodump for partial and logical restores.
What is the difference between mongodump and mongoexport?
mongodump produces BSON, preserving every MongoDB data type exactly, and is intended for backup and restore. mongoexport produces JSON or CSV for data interchange and loses type fidelity. Use mongodump for backups, mongoexport for reporting and integrations.
Need a second pair of eyes on your MongoDB backup and recovery setup, or want the restore drill automated in your CI pipeline? The team at coding4.net does exactly this kind of operational hardening work. Get in touch and we will review your current strategy.

