Cron Jobs Not Running
Diagnose and fix cron jobs that aren't executing, PATH issues, permissions, syntax errors, and silent failures.
Cron jobs failing silently is a common frustration. Here's a systematic approach to finding out why a job isn't running.
Step 1: Check Cron Service
# Debian/Ubuntu
systemctl status cron
# RHEL/CentOS/AlmaLinux
systemctl status crond
# Start if stopped
systemctl start cron
systemctl enable cronStep 2: Check Cron Logs
# Ubuntu/Debian
grep CRON /var/log/syslog | tail -30
# With journald
journalctl -u cron --since "1 hour ago"
journalctl -u crond --since today
# RHEL/CentOS
grep cron /var/log/cron | tail -30A successful run looks like:
cron[1234]: (root) CMD (/usr/local/bin/backup.sh)If you see the job in logs but it's failing, the issue is in the script itself. If you don't see it at all, the issue is with cron configuration.
Common Causes and Fixes
1. PATH Is Too Restrictive
Cron runs with a minimal PATH (/usr/bin:/bin). Commands available in your shell may not be found.
# Bad - 'node', 'python3', 'composer' may not be in cron's PATH
* * * * * node /app/script.js
# Good - use full paths
* * * * * /usr/bin/node /app/script.js
* * * * * /usr/bin/python3 /app/script.py
# Or set PATH at the top of crontab
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binFind the full path of a command:
which node
which python3
which composer2. Script Not Executable
# Check permissions
ls -la /usr/local/bin/backup.sh
# Fix
chmod +x /usr/local/bin/backup.sh
# Also ensure the script has a proper shebang
head -1 /usr/local/bin/backup.sh
# Should be: #!/bin/bash or #!/bin/sh3. Missing Newline at End of Crontab
POSIX requires a newline at the end of the crontab file. Without it, the last job is silently ignored.
# Always edit with:
crontab -e
# Never edit directly: /var/spool/cron/crontabs/root4. Output Going Nowhere (Silent Failures)
By default, cron emails output. If no mail agent is configured, output is lost.
# Redirect output to a log file
* * * * * /usr/local/bin/backup.sh >> /var/log/backup-cron.log 2>&1
# Discard all output (not recommended for debugging)
* * * * * /usr/local/bin/backup.sh > /dev/null 2>&1
# Suppress email for the whole crontab
MAILTO=""5. Wrong User's Crontab
# Check which user's crontab you're editing
crontab -l # current user
crontab -l -u nginx # specific user
# System-wide crontabs (include username field)
cat /etc/crontab
ls /etc/cron.d/6. Environment Variables Not Available
Cron doesn't source .bashrc, .profile, or /etc/environment:
# Set variables directly in the crontab
RAILS_ENV=production
DB_HOST=localhost
* * * * * /usr/bin/ruby /app/task.rb
# Or source the environment in the script
#!/bin/bash
source /etc/environment
source /home/user/.bashrc
# ... rest of script7. Crontab Syntax Error
# Validate your cron expression at https://crontab.guru
# Common mistakes:
# "every 5 minutes" → */5 * * * * (not 5 * * * *)
# "at 3am daily" → 0 3 * * *
# "every hour" → 0 * * * *8. Script Fails Due to Working Directory
Cron sets the working directory to $HOME. Relative paths in scripts fail:
# Bad
cd logs && ./process.sh
# Good
cd /var/www/myapp/logs && ./process.sh
# or
cd "$(dirname "$0")" && ./process.sh9. User Has No Login Shell
# Check the user's shell
grep www-data /etc/passwd
# www-data:x:33:33::/var/www:/usr/sbin/nologin ← can't run cron jobs
# Fix: change shell temporarily or run as a different user
crontab -u root -eTest a Job Manually as Cron Would Run It
# Simulate cron's environment
sudo -u www-data env -i HOME=/var/www SHELL=/bin/sh /bin/sh -c '/usr/local/bin/backup.sh'
# Or use run-parts to test a cron.d script
run-parts --test /etc/cron.dailysystemd Timers as a More Reliable Alternative
# Check existing timers
systemctl list-timers
# Timers log to journald: much easier to debug
journalctl -u myapp-backup.timer
journalctl -u myapp-backup.serviceSee the systemd timers guide for full setup instructions.
For servers that are not always running, use anacron (/etc/anacrontab) instead of standard cron. Anacron runs missed jobs on the next startup.
High I/O Wait - Disk Bottleneck Diagnosis
Identify and fix high iowait on Linux servers, find the responsible process, tune MySQL, Redis, and I/O schedulers.
Port Already in Use
Find and resolve "Address already in use" errors when a service fails to start because another process is bound to the same port.