Cron Expression Cheat Sheet: Syntax, Patterns, and Debugging
Cron is 50 years old and still the backbone of scheduled tasks on every Unix and Linux server. This guide takes you from "what are these five stars?" to writing expressions for every common schedule, running cron on our cPanel and DirectAdmin plans, and debugging jobs that silently refuse to run.
The five fields
┌─────────── minute (0 – 59)
│ ┌───────── hour (0 – 23)
│ │ ┌─────── day of month (1 – 31)
│ │ │ ┌───── month (1 – 12 or JAN – DEC)
│ │ │ │ ┌─── day of week (0 – 7; Sun = 0 or 7, or SUN – SAT)
│ │ │ │ │
* * * * * command-to-runEach of the five fields accepts:
| Syntax | Meaning | Example |
|---|---|---|
| Number | Exact value | 5 |
| Range | Every value in the range | 1-5 |
| List | Specific values | 1,15,30,45 |
| Step | Every N starting at 0 | */10 (every 10) |
| Step in range | Every N within a range | 0-30/5 (0, 5, 10, ..., 30) |
| Wildcard | Every value | * |
| Name (month / day-of-week only) | Abbreviated name | MON-FRI, JAN, DEC |
Common misreadings
These trip up even experienced developers:
- `*/5 * * * *` means "at minute 0, 5, 10, 15, ..." — so effectively "every 5 minutes". Not "every 5 of every hour of every day of every month of every day of week" (it is that, but the redundant wording confuses).
- `0 */2 * * *` means "at minute 0 of every 2nd hour". Not "every 2 minutes".
- `0 0 * * 0` means "midnight on Sunday". Not "the 1st day of every month".
When in doubt, paste your expression into crontab.guru — it translates to plain English and shows the next several fire times.
The everyday cheat sheet
Every-N-minutes
| Expression | Fires at |
|---|---|
* * * * * | Every minute |
*/5 * * * * | Every 5 minutes (:00, :05, :10, …) |
*/15 * * * * | Every 15 minutes (:00, :15, :30, :45) |
0,30 * * * * | :00 and :30 (equivalent to */30) |
0 * * * * | Top of every hour |
Hourly and daily
| Expression | Fires at |
|---|---|
0 */2 * * * | Every 2 hours (0:00, 2:00, 4:00, ...) |
0 9 * * * | 9:00 AM every day |
30 3 * * * | 3:30 AM every day |
0 */6 * * * | 4 times a day (0, 6, 12, 18) |
15 14 * * * | 2:15 PM every day |
Weekly patterns
| Expression | Fires at |
|---|---|
0 9 * * 1 | 9:00 AM every Monday |
0 9 * * 1-5 | 9:00 AM on weekdays (Mon–Fri) |
0 9 * * 0,6 | 9:00 AM on weekends (Sun, Sat) |
0 0 * * 0 | Midnight every Sunday |
0 18 * * 5 | 6:00 PM every Friday |
Monthly and yearly
| Expression | Fires at |
|---|---|
0 0 1 * * | Midnight on the 1st of every month |
0 0 15 * * | Midnight on the 15th |
0 0 1 */3 * | Quarterly — 1st of Jan, Apr, Jul, Oct |
0 0 1 1 * | Once a year, midnight Jan 1st |
30 23 L * * | 11:30 PM on the last day of month (extended cron only — not all systems support L) |
Shortcut names
Some cron implementations accept named shortcuts:
| Shortcut | Equivalent |
|---|---|
@reboot | Run once at system startup |
@hourly | 0 * * * * |
@daily | 0 0 * * * |
@weekly | 0 0 * * 0 |
@monthly | 0 0 1 * * |
@yearly / @annually | 0 0 1 1 * |
Our cPanel plans support the shortcuts. VPS Ubuntu / Debian also support them. RHEL / AlmaLinux support most.
Where to add cron jobs on Domain India hosting
cPanel
- Log in to cPanel → Home → Cron Jobs
- Use the "Common Settings" dropdown for quick presets, or type the 5-field expression
- Enter the command and click Add New Cron Job
- cPanel emails you the command output by default — useful for debugging, annoying at scale. Suppress with
>/dev/null 2>&1:
* * * * * cd /home/user/app && php artisan schedule:run >/dev/null 2>&1To capture output to a log instead:
* * * * * cd /home/user/app && php artisan schedule:run >> /home/user/cron.log 2>&1DirectAdmin
User panel → Cron Jobs. Same 5-field format. Some plans expose crontab -e via SSH — identical syntax.
Webuzo
Dashboard → Cron Jobs. Simple UI matching the cPanel pattern.
VPS (Ubuntu / Debian / AlmaLinux)
crontab -e # edit current user's crontab
crontab -l # list current entries
crontab -r # remove crontab (CAREFUL — no confirmation)System-wide crons go in:
/etc/cron.d/your-file— 6-field format (includes user)/etc/cron.hourly/— any executable file runs hourly/etc/cron.daily/— daily/etc/cron.weekly/— weekly/etc/cron.monthly/— monthly
systemd timers (modern alternative)
On modern VPS, systemd timers replace cron for many use cases:
- Proper logging via
journalctl - Dependency support (run job only after another service is up)
- Randomised start times (spread load)
- Better accuracy under system sleep
Covered in a future article in Background Jobs & Queues.
Real-world examples
Laravel scheduler
* * * * * cd /home/user/laravel-app && php artisan schedule:run >> /dev/null 2>&1This runs every minute and lets Laravel's App\Console\Kernel schedule internally (hourly, daily, etc.). One cron entry — all Laravel-defined jobs managed in code.
WordPress — offload wp-cron from page loads
By default WordPress fires wp-cron on every pageview, which is slow. Disable that and run it via system cron:
*/5 * * * * wget -q -O - https://yourdomain.com/wp-cron.php?doing_wp_cron >/dev/null 2>&1Add define('DISABLE_WP_CRON', true); to wp-config.php. Now wp-cron runs every 5 minutes reliably, regardless of traffic.
Database backup (mysqldump)
30 3 * * * /usr/bin/mysqldump -u dbuser -pdbpassword mydb | gzip > /home/user/backups/mydb-$(date +\%Y\%m\%d).sql.gzGotcha: % is treated as newline by cron. Escape it as \%. A % inside date +%Y%m%d without escaping breaks the command silently.
Cleanup logs older than 30 days
0 4 * * * find /home/user/logs/ -name "*.log" -mtime +30 -deleteRuns at 4:00 AM every day. -mtime +30 = modified more than 30 days ago.
Call an API webhook every 15 minutes
*/15 * * * * curl -s -X POST https://yourdomain.com/sync-external-api >/dev/nullDaily SSL expiry check
0 9 * * * /usr/bin/openssl s_client -servername yourdomain.com -connect yourdomain.com:443 2>/dev/null </dev/null | openssl x509 -noout -dates | mail -s "SSL expiry check" [email protected]Emails you the SSL expiry dates every morning. Replace with a Slack webhook call for team use.
Laravel queue worker (reliable restart)
*/5 * * * * cd /home/user/laravel-app && php artisan queue:work --stop-when-empty >/dev/null 2>&1Not ideal — for production queues, use a proper worker manager like PM2 or Supervisord. But on shared hosting where long-lived processes are not allowed, this cron-triggered approach works for light queue load.
Debugging cron jobs that don't run
The #1 Linux forum question. Checklist:
1. Is the cron daemon running?
On cPanel / DirectAdmin / Webuzo — yes, managed for you, always on.
On VPS:
systemctl status cron # Debian / Ubuntu
systemctl status crond # AlmaLinux / CentOS / RHELIf inactive, systemctl start crond (or cron) and enable on boot.
2. Is your crontab saved correctly?
crontab -lShows what's registered. If your expected entry is not there, re-save. If crontab -e said "errors in crontab file, can't install" on save, the expression is invalid.
3. Is the command path correct?
Cron runs with a minimal PATH environment variable — just /usr/bin:/bin. Use absolute paths:
# Bad: 'php' might not be found
* * * * * cd /home/user/app && php artisan schedule:run
# Better: use absolute path
* * * * * cd /home/user/app && /usr/local/bin/php artisan schedule:runOr set PATH at the top of your crontab:
PATH=/usr/local/bin:/usr/bin:/bin
* * * * * cd /home/user/app && php artisan schedule:runFind your PHP path with which php.
4. Is the command failing silently?
Redirect output to log and check:
* * * * * /path/to/script >> /home/user/cron.log 2>&1Then tail -f /home/user/cron.log to watch.
Also check system cron logs:
- cPanel / AlmaLinux:
/var/log/cron - Debian / Ubuntu:
/var/log/syslog— grep forCRON
5. Permission problems?
Scripts need execute permission:
chmod +x /home/user/myscript.shTest manually as the cron user:
sudo -u cronuser /home/user/myscript.shIf this fails, the cron will fail the same way.
6. Missing environment variable?
Cron doesn't source ~/.bashrc or ~/.profile. If your script needs env vars, set them explicitly:
* * * * * /bin/bash -c "source /home/user/.env && /path/to/script.sh"Or inline:
NODE_ENV=production
* * * * * /usr/bin/node /home/user/app/script.js7. % breaking the command?
Cron treats % as newline (as a way to pass stdin to commands). Escape with \%:
# Broken:
30 3 * * * mysqldump db > backup-$(date +%Y%m%d).sql
# Fixed:
30 3 * * * mysqldump db > backup-$(date +\%Y\%m\%d).sql8. Timezone confusion
Cron fires in the server's timezone. On our India-region servers that is usually IST (Asia/Kolkata). Verify:
date
timedatectl # on systemd-based VPSTo change on a VPS: sudo timedatectl set-timezone Asia/Kolkata.
On shared hosting the timezone is fixed by us — contact support if you need a different zone.
9. The job runs but overlaps itself
If your job takes longer than its interval, multiple copies pile up. Use flock to prevent overlap:
*/5 * * * * /usr/bin/flock -n /tmp/myjob.lock /path/to/script.shThe -n flag means "fail immediately if the lock is held", so the second run exits cleanly instead of piling up.
Security considerations for cron
- Don't put passwords in the crontab directly. They're visible to
ps -efduring execution. Source from an env file:source /home/user/.env && /path/to/script. - chmod env files 600 so only the owner can read them.
- Validate external inputs. If your cron curls a URL built from a variable, sanitise the variable first.
- Log responsibly. Make sure cron logs don't accidentally capture secrets.
- Review quarterly. Cron jobs have a way of accumulating — audit
crontab -levery three months and delete dead entries.
Useful external tools
- crontab.guru — visual expression explainer and next-fire-time calculator. Use every time you write a non-trivial expression.
- cronitor.io — cron monitoring; alerts if a job stops firing. Paid; free tier for < 5 jobs.
- Healthchecks.io — open-source alternative, free for personal use.
- Dead Man's Snitch — simple heartbeat monitoring.
Integration pattern: have your cron job curl a monitoring endpoint at the END of its run. If the monitoring service doesn't see the heartbeat within the expected window, it alerts you.
When cron is the wrong tool
Cron is great for scheduled tasks. It's the wrong tool when you need any of:
| Need | Use instead |
|---|---|
| Precision below 1 minute | Long-running process with sleep, OR systemd timers with OnUnitActiveSec=30s |
| Dependency chains (job A before job B) | Airflow, Temporal, GitHub Actions |
| Retry on failure | Background queues — see PM2 for Node.js |
| Process messages as they arrive | Queue consumer (long-lived) |
| "Run N minutes after this event" | Delay queue (Redis ZSET, BullMQ delay option) |
Frequently asked questions
What's the difference between cron and crontab?
Cron is the daemon that fires jobs. Crontab is the file (and the command crontab) that lists what jobs to fire. You edit the crontab; cron reads it.
Can I run a cron job every second?
No. Cron's minimum interval is one minute. For sub-minute scheduling use a long-running process with a loop + sleep, or systemd timers.
Why is my cron job emailing me thousands of messages?
Your job produces output on every run (STDOUT or STDERR), and cron emails anything it writes. Suppress with >/dev/null 2>&1 at the end of the command.
Can two cron jobs run at the same time?
Yes, by default. If you want to prevent concurrent runs of the same job, use flock as shown above.
How do I stop a running cron job?
Find it with ps -ef | grep your-script-name, then kill <PID>. If it's a flock-guarded job, killing the process will release the lock automatically.
What's `@reboot` in crontab?
A job that runs once when the system starts up. Useful for launching background processes, but fragile — the process dies when the VPS restarts and comes back. Prefer systemd or a proper process manager for long-lived services.
Does cron work correctly during DST transitions?
In regions with DST, cron jobs can either fire twice (fall-back) or be skipped (spring-forward). India doesn't observe DST, so this doesn't affect our servers — but be aware if you're migrating from a US or EU provider.
Do I need a VPS for running cron jobs?
No. Cron is available on all our cPanel, DirectAdmin, and Webuzo plans. You only need a VPS if the cron job requires long-running processes, heavy CPU, or system-level tools not available on shared hosting.
Questions on a specific cron pattern? [email protected] — we help customers debug cron jobs as part of standard support.