If your cron job is not running, the cause is almost always one of five things: cron uses a stripped-down environment (so your
PATH
and variables are missing), your schedule syntax is off by a field, the script isn't executable or has the wrong shebang, the crontab was never actually loaded, or the output errors are being silently discarded. The fastest way to find the real reason is to redirect your job's output to a log file and read what cron actually did.
Content Table
Confirm cron is actually running
Before blaming your script, check that the cron daemon itself is alive. On most Linux systems the service is called
cron
or
crond
.
# Debian/Ubuntu
systemctl status cron
# RHEL/CentOS/Fedora
systemctl status crond
# If it's not running:
sudo systemctl start cron
sudo systemctl enable cron
Next, confirm your crontab was actually saved. A surprising number of "cron not executing" reports come from editing a file that cron never reads. List the crontab for the current user:
crontab -l
If your job isn't there, you either edited the wrong file or forgot to save. Always use
crontab -e
to edit, never edit files under
/var/spool/cron
by hand.
sudo crontab -l
and your own
crontab -l
to see which one holds the job.
Capture the output so you can see the error
Cron runs silently. When a job fails, you get nothing on screen because there's no attached terminal. By default cron emails output to the user, but most servers have no mail configured, so errors vanish. Force the output somewhere you can read it:
* * * * * /home/user/backup.sh >> /tmp/cron.log 2>&1
The
2>&1
part is the key piece. It sends error messages (stderr) into the same log as normal output (stdout). Without it you'd only capture successful chatter and miss the actual failure.
You can also watch the system log to confirm cron even attempted your job:
# Debian/Ubuntu
grep CRON /var/log/syslog
# RHEL/CentOS
grep CRON /var/log/cron
# systemd systems
journalctl -u cron --since "10 minutes ago"
If you see your command listed in the log but it still didn't produce results, the problem is inside the script or its environment. If you see nothing at all, cron never triggered it, which points to a syntax or crontab-loading issue.
The environment problem (the #1 cause)
This is the reason most "why is my cron job not running" questions get posted. Cron runs jobs with a minimal environment. It is not your login shell, so it does not read
.bashrc
,
.bash_profile
, or your usual
PATH
. A script that works perfectly when you type it manually can fail under cron because a command it depends on can't be found.
Cron's default
PATH
is typically just
/usr/bin:/bin
. So a tool installed in
/usr/local/bin
(common for
node
,
python3
,
docker
,
aws
) simply isn't visible.
Fix it one of three ways:
-
Use absolute paths for everything.
Instead of
python3 script.py, write/usr/local/bin/python3 /home/user/script.py. Find the full path withwhich python3. - Set PATH inside the crontab. Add a line at the top of your crontab so all jobs inherit it.
- Source your environment at the start of the script. Useful when your job relies on many variables.
# Put this at the top of `crontab -e`
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
SHELL=/bin/bash
0 2 * * * /home/user/backup.sh >> /tmp/cron.log 2>&1
. /home/user/.env
at the top of the script.
Schedule syntax mistakes
A cron schedule has five time fields. Getting one wrong means your job either never fires or fires at the wrong time. The fields, in order:
| Field | Range | Notes |
|---|---|---|
| Minute | 0-59 | First field |
| Hour | 0-23 | 24-hour clock |
| Day of month | 1-31 | Combine carefully with day of week |
| Month | 1-12 | Or Jan-Dec |
| Day of week | 0-7 | 0 and 7 both mean Sunday |
Common syntax slip-ups:
- Using the wrong number of fields. Five fields, then the command. A six-field job (with seconds) is not standard cron and will be misread.
-
Confusing
*/5with5.*/5 * * * *means every 5 minutes;5 * * * *means once an hour at minute 5. -
Both day-of-month and day-of-week set.
When both are specified (not
*), cron runs the job if either matches, which often surprises people. -
Unescaped percent signs.
A literal
%in the command is treated as a newline by cron. Escape it as\%, which trips up jobs usingdate +%Y-%m-%d.
Validate your timing expression against the official crontab(5) man page if you're unsure how a field behaves.
Permission and executable issues
A "crontab permission denied" error usually means your script lacks the execute bit or cron can't read a file it needs. Walk through these:
-
Make the script executable:
chmod +x /home/user/backup.sh. -
Include a shebang.
The first line must declare the interpreter, e.g.
#!/bin/bashor#!/usr/bin/env python3. Without it, cron doesn't know how to run the file. -
Check who owns the job.
A script that touches files in
/rootwon't work from a user crontab. Match the crontab owner to the permissions the script needs. -
Confirm cron access isn't restricted.
Files named
/etc/cron.allowand/etc/cron.denycontrol which users may schedule jobs. If your user is incron.deny(or missing fromcron.allow), your crontab is ignored entirely.
Also watch for line-ending problems. If you wrote the script on Windows, it may have carriage-return characters (
\r
) that break the shebang. Clean them with
sed -i 's/\r$//' script.sh
or run the file through
dos2unix
.
* * * * *
(every minute), point output to a log, wait 60 seconds, then read the log. Once it works, restore your real schedule. This turns hours of guessing into a one-minute feedback loop.
Quick troubleshooting checklist
Run through these in order and you'll catch the vast majority of cron failures:
-
Is the cron daemon running? (
systemctl status cron) -
Is the job actually in the crontab? (
crontab -l) - Are you looking at the right user's crontab (yours vs. root)?
-
Is output being logged with
>> file 2>&1? - Does the system log show cron attempting the job?
-
Do all commands use absolute paths, or is
PATHset in the crontab? -
Is the schedule syntax correct (five fields, escaped
%)? - Is the script executable with a valid shebang?
-
Is your user allowed by
cron.allow/cron.deny? - Does the file have Unix line endings?
Need help with your cron schedule?
Use our free online cron expression builder to create, test, and validate your cron schedules in seconds. Perfect for developers who want to avoid syntax errors and ensure their jobs run at the right time.
Try Our Free Tools →
Because cron uses a minimal environment that skips your shell profile. Your
PATH
and environment variables aren't loaded, so commands in
/usr/local/bin
or custom variables go missing. Use absolute paths, set
PATH
in the crontab, or source an env file inside your script.
Redirect output to a log file by appending
>> /tmp/cron.log 2>&1
to the job. The
2>&1
captures error messages too. You can also check
/var/log/syslog
or run
journalctl -u cron
to confirm cron attempted the job at all.
It usually means the script isn't executable or your user is blocked from using cron. Run
chmod +x
on the script, add a valid shebang line, and check that your username isn't listed in
/etc/cron.deny
or missing from
/etc/cron.allow
.
No. When you save with
crontab -e
, cron detects the change automatically and picks up the new schedule. You only need to restart the daemon if the service itself stopped or if you edited system files under
/etc/cron.d
in some setups.
Most often it's a syntax slip or a timezone mismatch. Confirm the five fields are in the right order and remember cron uses the system timezone, not your local one. Check with
timedatectl
and set
CRON_TZ=
at the top of the crontab if you need a specific zone.