The Situation
You set up a crontab entry, wait for it to fire, and nothing happens. No output. No log. No error. Then you check /var/log/syslog (or /var/log/cron on RHEL/CentOS) and find this:
CRON[12345]: (root) CMD (/opt/scripts/backup.sh)
CRON[12345]: (CRON) info (no MTA installed, discarding output)
Here's the thing โ the job did run. Cron executed it. But any output the script produced got silently dropped because there's no mail transfer agent installed to deliver it. If your script exited with error code 1, you'd never know.
Why This Happens
Cron was designed to email job output to the crontab owner. On a minimal Ubuntu or CentOS server install, no MTA (like postfix, sendmail, or ssmtp) exists โ so cron logs that warning and throws the output away.
In production, that's a problem. Your backup script could be failing every night at 2am, and you'd have zero trace of it.
Quick Fix: Redirect Output in the Crontab
No package installs needed. Just redirect stdout and stderr directly in the crontab entry:
# Append all output to a log file
*/5 * * * * /opt/scripts/backup.sh >> /var/log/backup-cron.log 2>&1
# Discard all output (only use if the script has its own logging)
*/5 * * * * /opt/scripts/backup.sh > /dev/null 2>&1
Once cron has nowhere to mail the output, the MTA warning stops appearing.
Which option fits your case:
- Use
>> /var/log/backup-cron.log 2>&1if your script has no internal logging. You'll want a record โ especially when something breaks at 3am. - Use
> /dev/null 2>&1only if the script already writes its own structured logs, or you genuinely don't need the output.
Verify the Fix
After updating the crontab, wait for the next scheduled run and check syslog:
# Watch for cron activity in real time
tail -f /var/log/syslog | grep CRON
# On RHEL/CentOS
tail -f /var/log/cron
A clean run looks like this โ the CMD line appears, with no MTA warning after it:
CRON[12346]: (root) CMD (/opt/scripts/backup.sh)
Then confirm your log file is getting written to:
tail -f /var/log/backup-cron.log
Permanent Fix: Set MAILTO at the Top of the Crontab
Managing five cron jobs? Adding 2>&1 redirects to each line gets tedious fast. A cleaner approach: set MAILTO to empty once at the top of the file. Cron skips mail delivery for every job in that file.
crontab -e
MAILTO=""
*/5 * * * * /opt/scripts/backup.sh >> /var/log/backup-cron.log 2>&1
0 2 * * * /opt/scripts/db-dump.sh >> /var/log/db-dump.log 2>&1
30 6 * * 1 /opt/scripts/weekly-report.sh >> /var/log/weekly.log 2>&1
Keep the >> logfile 2>&1 redirects anyway โ MAILTO="" silences the warning, but you still need output going somewhere useful.
If the Job Is Truly Not Running
The no MTA installed message is actually reassuring โ it confirms the job executed. But if there's no CMD line in syslog at all, something else is wrong. Work through these checks:
1. Confirm cron daemon is running
# Debian/Ubuntu
systemctl status cron
# RHEL/CentOS
systemctl status crond
Stopped? Start it: sudo systemctl start cron (or crond).
2. Check crontab syntax
crontab -l
Three mistakes that silently break crontabs:
- Missing trailing newline โ the last entry in the file must end with a newline, or cron ignores it
- Bare
%signs โ cron treats%as a newline character. Escape it as\%in commands likedate +%Y-%m-%d - Wrong field order โ the format is
minute hour day month weekday command
Not sure if cron is working at all? Drop in a test job that fires every minute:
* * * * * echo "cron alive $(date)" >> /tmp/cron-test.log 2>&1
If /tmp/cron-test.log gets a new line every 60 seconds, cron is healthy and the problem is in your script.
3. Check script permissions
ls -l /opt/scripts/backup.sh
chmod +x /opt/scripts/backup.sh
The script must be executable. Also check that the user who owns the crontab can actually read and execute the file โ especially if the script lives in a directory with restricted permissions.
4. PATH is minimal inside cron
Cron's default PATH is typically just /usr/bin:/bin. Commands that work fine in your shell โ python3, aws, node โ may not be found at all. Two ways to handle it:
# Option A: set PATH at the top of crontab
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
*/5 * * * * /opt/scripts/backup.sh >> /var/log/backup-cron.log 2>&1
# Option B: use absolute paths inside the script
/usr/bin/python3 /opt/scripts/process.py
5. Environment variables aren't loaded
Cron doesn't source .bashrc or .bash_profile. Variables like AWS_PROFILE, JAVA_HOME, or DATABASE_URL won't exist unless you set them explicitly. Add this at the top of your script:
#!/bin/bash
source /etc/environment
# or set variables directly
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
export AWS_PROFILE=production
Quick Reference
- See the warning, job ran: Add
>> /logfile 2>&1to the crontab entry, or setMAILTO=""at the top - No CMD line in syslog: Check daemon status, crontab syntax, file permissions, and PATH
- Works manually but not via cron: Almost always PATH or a missing environment variable

