Your cron job is not running and you have grepped /var/log/syslog three times. Work through these eight checks in order. They fix most broken crons without guessing.
TL;DR: (1) cron daemon running, (2) valid crontab syntax, (3) PATH in cron, (4) script executable, (5) cron logs, (6) script exits non-zero, (7) timezone, (8) host throttling. Then stop relying on the box alone.
For Linux basics, see What is a cron job in Linux?. For WordPress-specific queues, see WooCommerce cron not running.
Step 1: Is the cron daemon running?
On systemd Linux:
systemctl status cron
# or on some distros:
systemctl status crondIf it is inactive, start it:
sudo systemctl start cron
sudo systemctl enable cronIn Docker without a cron daemon, nothing will run crontab entries. Use external HTTP cron or a platform scheduler instead.
Step 2: Check the crontab syntax
crontab -lValidate the expression in the free cron debugger. Common mistakes:
- Five fields, not six (unless your scheduler is Quartz-style)
- Day-of-week
0and7both mean Sunday; do not mix carelessly - Day-of-month and day-of-week together use OR logic on many systems
Step 3: Check PATH inside cron
Cron runs with a minimal environment. This fails:
0 2 * * * python3 /opt/sync.pyThis works:
0 2 * * * /usr/bin/python3 /opt/sync.pyOr set at the top of the crontab file:
PATH=/usr/local/bin:/usr/bin:/binStep 4: Check file permissions
The script must be executable (for direct invocation) or explicitly called with an interpreter:
chmod +x /opt/sync.py
# first line: #!/usr/bin/python3Cron runs as the user who owns the crontab. Root crontab vs user crontab matters for file ownership.
Step 5: Check the cron log
Debian/Ubuntu:
grep CRON /var/log/syslogjournalctl:
journalctl -u cron --since todaymacOS:
log show --predicate 'process == "cron"' --last 1hIf there is no CRON line at the expected minute, cron did not attempt the job (syntax, user, or daemon issue).
Step 6: Check that the script actually exits
Run the exact command line as the crontab user:
sudo -u www-data /usr/bin/python3 /opt/sync.py
echo $?Non-zero exit codes may still email the crontab owner on some systems. Silent hangs (waiting for input, deadlocked DB) look like "cron ran" in logs but accomplish nothing.
Step 7: Check timezone
crontab uses the system timezone unless you set CRON_TZ= (where supported). A job at 0 2 * * * is 2am in the server's zone, not yours.
Platform cron (GitHub Actions, Vercel) often forces UTC. See GitHub Actions cron drift.
Step 8: Check throttling (containers, shared hosts)
Shared hosts kill long jobs. Kubernetes may forbid overlapping CronJobs. GitHub Actions queues or drops scheduled workflows under load.
If the platform ate your fire, no amount of crontab debugging on a laptop fixes production. Move the clock to Crontap or the platform's native scheduler.
Fix this in 60 seconds with Crontap. Free forever tier. Three schedules. No credit card. Schedule your first job →
Why this keeps happening (and how to stop guessing)
Local cron fails quietly when:
- The server reboots and nobody verifies crontab survived
- Deploy scripts overwrite the machine without migrating cron
- The job depends on visitor traffic (WordPress wp-cron)
- The schedule was paused in a dashboard you forgot about
Structural fix: external HTTP cron with built-in run logs and failure alerts. Crontap retries on 5xx, shows the response body, and pages you when the retry budget is gone. For "the run never happened at all," pair with a dead-man check per Dead man's switch, explained for developers.
FAQ
Cron says it ran but nothing changed
The command probably exited 0 without doing work (wrong env, wrong DB URL, feature flag off). Compare manual run vs cron run environment (env > /tmp/cron-env.txt in the job).
Works manually but not in crontab
Almost always PATH, permissions, or user context. Less often: different shell (use absolute paths).
How often should I check cron logs?
You should not have to. Use alerts. Crontap uptime for URLs; schedule failure alerts for HTTP jobs.
Related on Crontap
- Cron job monitoring. Failure alerts, run history, and when to add a dead-man check.
- Python cron jobs
- cPanel cron jobs
- Docker cron jobs
- Monitoring heartbeats
Fix this in 60 seconds with Crontap. Free forever tier. Three schedules. No credit card. Schedule your first job →
