Skip to content
Commitpedia
Log in Join & edit

Nightly mongodump backup with rotation

A bash script for cron that writes a compressed mongodump archive each night, keeps the password out of the process list, checks the file and deletes archives older than N days.

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?

Edit history of Nightly mongodump backup with rotation: 1 recorded edit
Edit history · 1 edit
Type
Script
Edits
1
Editors
1
First issued
15 Oct 2026
Last edit
15 Oct 2026
Language
bash
Licence
CC0-1.0

What this changes

Creates /var/backups/mongodb (mode 700) with a .lock file, writes mongodb-STAMP.archive.gz and a .sha256 file, then permanently deletes archives and checksums there older than KEEP_DAYS (default 14). The database is only read.

How to undo it

Delete an archive with rm /var/backups/mongodb/mongodb-STAMP.archive.gz*. Rotated archives cannot be recovered: copy them elsewhere or raise KEEP_DAYS before running.

mongodump exports the contents of a running MongoDB deployment to BSON, and mongorestore loads it back. MongoDB recommends this pair for small deployments; for large or busy ones, filesystem or block-level snapshots are less disruptive. If a dump suits your size, this script runs it every night, writes one compressed archive file per run and removes old ones.

Prepare a backup user and a password file

Create a dedicated user with the built-in backup role (see the MongoDB authentication guide), then store its password in a YAML file that only the backup account can read. mongodump --config reads the password from there, so it never appears on the command line, where other users could see it with ps.

Check before you run this

  • Runs with administrator rights. Make sure you understand every line.
sudo mkdir -p /etc/mongodb-backup
sudo install -m 600 -o backup -g backup /dev/null /etc/mongodb-backup/mongodump.yaml
sudoedit /etc/mongodb-backup/mongodump.yaml
password: CHANGE_ME

The examples assume a local system account named backup that runs the job. Use whichever unprivileged account you prefer.

The script

#!/usr/bin/env bash
# mongo-nightly-backup.sh: nightly mongodump archive with rotation. License: CC0-1.0
set -euo pipefail

MONGO_HOST="${MONGO_HOST:-127.0.0.1}"
MONGO_PORT="${MONGO_PORT:-27017}"
MONGO_USER="${MONGO_USER:-backup}"
AUTH_DB="${AUTH_DB:-admin}"
CONFIG_FILE="${CONFIG_FILE:-/etc/mongodb-backup/mongodump.yaml}"
BACKUP_DIR="${BACKUP_DIR:-/var/backups/mongodb}"
KEEP_DAYS="${KEEP_DAYS:-14}"
USE_OPLOG="${USE_OPLOG:-no}"

log() { printf '%s %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"; }
die() { log "ERROR: $*" >&2; exit 1; }

command -v mongodump >/dev/null 2>&1 || die "mongodump not found in PATH"
command -v flock >/dev/null 2>&1 || die "flock not found (package util-linux)"
[[ -r "$CONFIG_FILE" ]] || die "cannot read $CONFIG_FILE"
perms=$(stat -c '%a' "$CONFIG_FILE")
case "$perms" in
  400|600) ;;
  *) die "$CONFIG_FILE holds a password, set it to mode 600 (now $perms)" ;;
esac
if ! [[ "$KEEP_DAYS" =~ ^[0-9]+$ ]] || (( KEEP_DAYS < 1 )); then
  die "KEEP_DAYS must be a whole number of at least 1"
fi

mkdir -p "$BACKUP_DIR"
chmod 700 "$BACKUP_DIR"
exec 9>"$BACKUP_DIR/.lock"
flock -n 9 || die "another backup is still running"

stamp=$(date '+%Y%m%d-%H%M%S')
final="$BACKUP_DIR/mongodb-$stamp.archive.gz"
tmp="$final.partial"
trap 'rm -f "$tmp"' EXIT

args=(
  --host="$MONGO_HOST"
  --port="$MONGO_PORT"
  --username="$MONGO_USER"
  --authenticationDatabase="$AUTH_DB"
  --config="$CONFIG_FILE"
  --archive="$tmp"
  --gzip
)
if [[ "$USE_OPLOG" == "yes" ]]; then
  args+=(--oplog)
fi

log "dumping $MONGO_HOST:$MONGO_PORT to $final"
mongodump "${args[@]}"

[[ -s "$tmp" ]] || die "archive is empty"
gzip -t "$tmp" || die "archive failed the gzip integrity test"
mv "$tmp" "$final"
sha256sum "$final" > "$final.sha256"
log "finished: $(du -h "$final" | cut -f1)"

log "deleting backups older than $KEEP_DAYS days"
find "$BACKUP_DIR" -maxdepth 1 -type f \
  \( -name 'mongodb-*.archive.gz' -o -name 'mongodb-*.archive.gz.sha256' \) \
  -mtime +"$KEEP_DAYS" -print -delete
log "kept: $(find "$BACKUP_DIR" -maxdepth 1 -name 'mongodb-*.archive.gz' | wc -l) archive(s)"

How it works

  • Settings come from environment variables with safe defaults, so you can reuse the script for several servers.
  • It refuses to run if the password file is readable by others, and flock stops two runs from overlapping.
  • --archive with --gzip writes the whole dump as one compressed file. It is written under a .partial name and renamed only after it passed gzip -t, so a half-written file never looks like a good backup.
  • A .sha256 file is stored next to each archive, so you can verify copies after moving them to another site.
  • Rotation runs only after a successful dump, because set -e stops the script at the first error. A broken night never deletes your older good backups.

Replica sets and the –oplog option

Without --oplog, writes that happen during the dump mean the result does not reflect one single moment. On a replica set member, set USE_OPLOG=yes: mongodump then also captures oplog entries written during the dump, and mongorestore --oplogReplay replays them for a point-in-time result. --oplog works only for a full dump of a replica set member; it does not work on a standalone server or on a sharded cluster (follow MongoDB’s sharded-cluster backup procedure there).

Schedule it

Check before you run this

  • Runs with administrator rights. Make sure you understand every line.
sudo install -m 750 -o root -g backup mongo-nightly-backup.sh /usr/local/bin/

# /etc/cron.d/mongodb-backup
MONGO_HOST=127.0.0.1
KEEP_DAYS=14
30 2 * * * backup /usr/local/bin/mongo-nightly-backup.sh >> /var/log/mongodb-backup.log 2>&1

Run it once by hand as the backup user and read the output before trusting cron with it.

Restore and test

A backup you never restored is not proven. Restore into a separate test server regularly. --nsFrom and --nsTo rename databases during the restore, so you can load a copy next to existing data without touching it:

sha256sum -c /var/backups/mongodb/mongodb-20260115-023000.archive.gz.sha256

mongorestore --host=test-db.example.com --username=admin --authenticationDatabase=admin \
  --gzip --archive=/var/backups/mongodb/mongodb-20260115-023000.archive.gz \
  --nsInclude='shop.*' --nsFrom='shop.*' --nsTo='shop_restoretest.*'

--drop deletes each target collection before restoring it, and when the restore includes the admin database it also replaces all users with those in the dump. Never point a restore with --drop at production unless you mean to overwrite it; check the host name in the command and do a --dryRun first.

Things to adjust

  • Copy the archives off the database host as well (another server, object storage), so one lost machine does not take the data and its backups.
  • Add monitoring that alerts when the newest archive is older than a day, so a silently failing job is noticed.
  • mongodump cannot back up collections that use Queryable Encryption or Client-Side Field Level Encryption.

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

Repos in the wild

History

Every saved edit is kept. The plot on the sleeve draws one line per edit. Open any edit to see exactly what changed.

  1. Dominik +6,760 chars

Report a problem

Something wrong, unsafe or copied? Tell the editors.
What is wrong?