Alert when your backup stops running — before you need it
Last updated: July 2026 · By Yohann Kipfer, Cron-Ping
The dangerous backup failure isn't « the dump errored ». It's « the dump never even started — for weeks — and nobody knew ». A full disk, an expired SSH key, a crontab wiped by a server rebuild: the backup silently stops, and you find out the day you try to restore. Add a ping that fires only when the backup succeeds, and let its absence alert you:
0 2 * * * /opt/backup.sh && curl -fsS https://cron-ping.com/p/TOKENThe && is the whole trick: curl runs only if backup.sh exits 0. If the script fails or never runs at all, no ping reaches Cron-Ping, and when the grace period passes you get an email. A backup that isn't monitored isn't a backup — it's a hope.
The nightmare scenario is silence, not an error
Most teams that lose data didn't have « no backups ». They had backups that had been silently broken for months. The classic chain: the backup target disk fills up, or the offsite SSH key expires, or a server rebuild drops the crontab line — and the nightly job either errors into /dev/null or never fires. Everything looks normal. The dashboards are green. Then a disk dies, someone runs the restore, and the newest usable copy is from before the problem started.
A monitor doesn't make backups; it makes their absence loud. That's the missing half of every backup script.
Ping on success — one line per tool
Chain the ping with && so it only fires on a clean exit (code 0). Here's the pattern for the common tools:
| Tool | Line |
|---|---|
| mysqldump | mysqldump --single-transaction db | gzip > d.sql.gz && curl -fsS …/p/TOKEN |
| pg_dump | pg_dump -Fc db > d.dump && curl -fsS …/p/TOKEN |
| rsync | rsync -a /data/ backup:/srv/ && curl -fsS …/p/TOKEN |
| borg | borg create ::'{now}' /data && curl -fsS …/p/TOKEN |
| restic | restic backup /data && curl -fsS …/p/TOKEN |
curl -fsS is deliberate: -f fails on an HTTP error, -s is silent, -S still shows an error if something breaks — so the curl itself won't quietly fail. Give the Cron-Ping check the same period as the backup (daily → 1 day, weekly → 7 days) and a grace period generous enough to cover a slow night without hiding a truly missed run.
A clean exit code is not a good backup — check the size
mysqldump can exit 0 and still hand you a broken dump. Two real traps: with --force it keeps going past a table error and still exits 0, and a dump interrupted by the connection dropping can leave a truncated file with a 0 exit if buffering hides it. The fix is to verify the artifact, not just the exit code — and send /fail when it's empty:
#!/bin/bash
set -o pipefail
OUT=/backup/db-$(date +%F).sql.gz
mysqldump --single-transaction --quick app | gzip > "$OUT"
# a real backup is never a few bytes — 0-byte or tiny = failure
if [ -s "$OUT" ] && [ "$(stat -c%s "$OUT")" -gt 1024 ]; then
curl -fsS https://cron-ping.com/p/TOKEN
else
curl -fsS https://cron-ping.com/p/TOKEN/fail
fiset -o pipefail matters here: without it, mysqldump | gzip returns gzip's exit code, so a failed dump piped into a successful gzip looks like success. With pipefail, the pipeline fails if any stage fails.
Measure the run, and read the tool's own exit codes
Ping /start at the top and /success at the end, and Cron-Ping records the *duration*. A nightly pg_dump that has crept from 4 minutes to 40 is telling you the database grew — useful long before it becomes a failed 3 a.m. job. And borg and restic have richer exit codes than 0/1 that are worth branching on:
| Code | borg | restic |
|---|---|---|
| 0 | success | success |
| 1 | warning (backup completed with warnings) | general error — backup failed |
| 2 | error — backup failed | Go runtime error |
| 3 | — | some source files could not be read (partial backup) |
A borg exit of 1 (warning) or a restic exit of 3 (partial) is exactly the « ran, but not really » state that a plain && would count as success. Branch on the code and send /fail so a partial backup doesn't masquerade as a good one.
The rest of the insurance: 3-2-1, encryption, and testing the restore
- *Follow 3-2-1. Three copies of the data, on two different media, one of them offsite. A monitored nightly dump that lives on the same disk as the database satisfies none* of the three when that disk dies.
- *Test the restore, on a schedule. A backup you have never restored is a theory. Periodically restore into a throwaway container and check row counts or a known record. Wrap that* job in its own Cron-Ping check too — so « nobody has tested the restore in 90 days » becomes an alert.
- *Encrypt offsite copies.*
resticandborgencrypt by default; a rawmysqldumprsync'd offsite does not. An unencrypted database dump on someone else's storage is a breach waiting to happen. - *Watch retention. A retention rule that prunes too aggressively can erase the last good copy right after a bad run. Keep enough history that you can go back past* the moment a silent failure started.
FAQ
How do I get an alert if my backup stops running?
Add && curl -fsS https://cron-ping.com/p/TOKEN to the end of the backup command and create a check whose period matches the schedule. The ping only fires on a successful backup; if the backup fails or never runs, no ping arrives, and once the grace period elapses Cron-Ping emails or Slacks you. That covers the case internal tools can't: a job that never started.
My backup script exits 0 but the dump is empty — how do I catch that?
Check the artifact, not just the exit code. Test the file size ([ -s file ] and a minimum byte count) before pinging success, and hit the /fail endpoint when it's too small. Also use set -o pipefail so a failed mysqldump | gzip doesn't report gzip's success as the whole pipeline's.
What period and grace should I set for a nightly backup?
Period = 1 day for a nightly job, 7 days for a weekly one. Grace has to cover a normal run's duration plus a bit of slack — if the dump usually takes 20 minutes, a 1-2 hour grace absorbs a slow night without hiding a run that genuinely didn't happen. For a weekly backup a grace of several hours to a day is reasonable.
Does this work with restic and borg?
Yes. Chain the ping after restic backup or borg create. Better still, branch on their exit codes: a borg exit of 1 (warning) or a restic exit of 3 (some files unreadable) is a partial backup you want to treat as a failure and send to /fail, not count as green.
Isn't a green backup log enough?
No — a log only exists if the job ran, and you'd have to be reading it. The failures that cost people data are the ones where the job silently stopped: a wiped crontab, a full disk, an expired key. There's no error log for a job that never fired. A missed heartbeat is the only signal that reaches you without you looking.
Get an email the day your backup stops — not the day you need it
Add one && curl to your backup script and set a check to its schedule. If the dump fails, runs empty, or never starts, the ping doesn't arrive and Cron-Ping alerts you — while there's still a good copy to fall back on.
Free plan: 10 checks, email alerts, 7-day history. No card. EU-hosted.