Database backup alerts

Database backup failure alerts to your phone.

Your nightly pg_dump failed at 3 AM and nobody noticed for two weeks. Not anymore.

The silent disaster

Backups fail silently. A disk fills up, a password rotates, a network changes — and your nightly cron keeps exiting non-zero without anyone knowing. When you need the backup, it does not exist. Nerve sends a push the moment it fails.

PostgreSQL (pg_dump)

#!/bin/bash
set -euo pipefail
export NERVE_DSN="nerve://TOKEN:[email protected]"
DB="production"
BACKUP_DIR="/var/backups/postgres"
TIMESTAMP=$(date +%Y%m%d_%H%M)

if pg_dump "$DB" | gzip > "$BACKUP_DIR/${DB}_${TIMESTAMP}.sql.gz"; then
  SIZE=$(du -h "$BACKUP_DIR/${DB}_${TIMESTAMP}.sql.gz" | cut -f1)
  echo "Backup OK: $DB ($SIZE) on $(hostname)" | nerve send
else
  echo "BACKUP FAILED: pg_dump $DB on $(hostname)" | nerve send --severity critical
fi

MySQL / MariaDB (mysqldump)

#!/bin/bash
set -euo pipefail
export NERVE_DSN="nerve://TOKEN:[email protected]"
DB="app_production"
BACKUP_DIR="/var/backups/mysql"
TIMESTAMP=$(date +%Y%m%d_%H%M)

if mysqldump --single-transaction "$DB" | gzip > "$BACKUP_DIR/${DB}_${TIMESTAMP}.sql.gz"; then
  echo "Backup OK: $DB on $(hostname)" | nerve send
else
  echo "BACKUP FAILED: mysqldump $DB on $(hostname)" | nerve send --severity critical
fi

MongoDB (mongodump)

#!/bin/bash
set -euo pipefail
export NERVE_DSN="nerve://TOKEN:[email protected]"
DB="app"
BACKUP_DIR="/var/backups/mongo"
TIMESTAMP=$(date +%Y%m%d_%H%M)

if mongodump --db="$DB" --archive="$BACKUP_DIR/${DB}_${TIMESTAMP}.gz" --gzip; then
  echo "Backup OK: mongo/$DB on $(hostname)" | nerve send
else
  echo "BACKUP FAILED: mongodump $DB on $(hostname)" | nerve send --severity critical
fi

Check backup age (dead man's switch)

Catch silently broken backup crons: alert if the latest backup is older than expected.

#!/bin/bash
export NERVE_DSN="nerve://TOKEN:[email protected]"
BACKUP_DIR="/var/backups/postgres"
MAX_AGE_HOURS=26  # Nightly backup should be less than 26 hours old

LATEST=$(find "$BACKUP_DIR" -name "*.sql.gz" -type f -printf '%T@\n' | sort -n | tail -1)
if [ -z "$LATEST" ]; then
  echo "NO BACKUPS FOUND in $BACKUP_DIR on $(hostname)" | nerve send --severity critical
  exit 1
fi

AGE_HOURS=$(( ($(date +%s) - ${LATEST%.*}) / 3600 ))
if [ "$AGE_HOURS" -gt "$MAX_AGE_HOURS" ]; then
  echo "STALE BACKUP: latest is ${AGE_HOURS}h old on $(hostname)" | nerve send --severity critical
fi

Check backup size (catch empty dumps)

LATEST_FILE=$(ls -t /var/backups/postgres/*.sql.gz 2>/dev/null | head -1)
if [ -n "$LATEST_FILE" ]; then
  SIZE=$(stat -c%s "$LATEST_FILE")
  if [ "$SIZE" -lt 1000 ]; then
    echo "SUSPICIOUS BACKUP: $LATEST_FILE is only $SIZE bytes" | nerve send --severity alert
  fi
fi

Crontab

# Nightly backup at 2:30 AM
30 2 * * * /usr/local/bin/backup-postgres-nerve.sh

# Check backup age at 8 AM
0 8 * * * /usr/local/bin/check-backup-age.sh

Quick start

go install github.com/nerve-ink/nerve-cli/cmd/nerve@latest
export NERVE_DSN="nerve://TOKEN:[email protected]"
echo "BACKUP FAILED: pg_dump production on db-1" | nerve send --severity critical

FAQ

How do I get notified when a database backup fails?

Wrap your dump command in a script that checks the exit code and pipes a failure message to nerve send.

Can I also confirm successful backups?

Yes. Send a signal on success too — if you stop getting success signals, something is wrong with the entire cron chain.

Is my database connection info exposed?

Never include credentials in the alert. Send only the database name, status, and timestamp. Nerve encrypts the payload, but keeping secrets out of the message is good hygiene.