Three years ago, I woke up at 2 AM to a frantic message from my boss. Our database backup had failed again—the third time that month. I’d been running the backup script manually before leaving work each day, and on Friday I forgot. That Monday morning disaster taught me a lesson I should have learned years earlier: if you’re doing something more than once, automate it.
That’s exactly what cron jobs do. They’re Linux’s built-in task scheduler, running commands and scripts at specific times without any human intervention. Whether you need to backup databases at midnight, clean temporary files every hour, or send weekly reports on Sunday mornings, cron handles it all.
In this guide, I’ll show you how to schedule cron jobs in Linux, avoid the common mistakes that trip up beginners, and share the practical patterns I use every day managing production servers.

What is a Cron Job and Why Should You Care?
A cron job is a scheduled task that runs automatically at specific intervals on Linux systems. The name comes from “chronos,” the Greek word for time. The cron daemon runs continuously in the background, checking every minute to see if any jobs need to execute.
Think of cron as your system’s personal assistant. You tell it once what to do and when, and it remembers forever. No more sticky notes, no more forgotten tasks, no more logging in at midnight to run backups manually.
Here’s what makes cron invaluable for system administration:
- Reliability: Cron runs tasks exactly when scheduled, even if you’re asleep or on vacation
- Simplicity: Once you understand the syntax, scheduling tasks takes seconds
- Universality: Cron exists on virtually every Unix-like system, from your Raspberry Pi to enterprise servers
- Flexibility: Schedule anything from simple commands to complex shell scripts
I use cron jobs for database backups, log rotation, monitoring checks, certificate renewals, and automated reports. Every task I’ve automated with cron is one less thing that can go wrong from human error.
Understanding Crontab Syntax: The Five Fields
The crontab (cron table) is where you define your scheduled jobs. Each line in a crontab file represents one job, following this format:
minute hour day month weekday command * * * * * /path/to/script.sh
Those five asterisks represent time fields. Here’s what each one controls:
- Minute (0-59): Which minute of the hour
- Hour (0-23): Which hour of the day (0 = midnight, 23 = 11 PM)
- Day of Month (1-31): Which day of the month
- Month (1-12): Which month of the year
- Day of Week (0-7): Which day of the week (0 and 7 are both Sunday)
An asterisk means “every.” So five asterisks means “every minute of every hour of every day.” That’s probably not what you want, unless you enjoy overwhelming your system.
Special Characters You’ll Actually Use
Beyond the asterisk, cron syntax uses a few special operators that make scheduling flexible:
- Comma (,): Separate multiple values.
0,30in the minute field means “at minute 0 and minute 30” - Dash (-): Define a range.
9-17in the hour field means “9 AM through 5 PM” - Slash (/): Specify intervals.
*/5in the minute field means “every 5 minutes”
The best tool for validating cron syntax is Crontab Guru. I keep it bookmarked and use it every time I write a new cron expression. It translates cryptic syntax into plain English instantly.
How to Create Your First Cron Job
Let’s walk through creating a real cron job from scratch. I’ll show you how to schedule a simple backup script that runs every night at 2 AM.
Step 1: Edit Your Crontab
Open your user’s crontab file with this command:
crontab -e
The first time you run this, Linux might ask which text editor you prefer. I use vim, but nano is easier for beginners. Choose nano if you’re unsure.
Step 2: Add Your Cron Job
Add this line to schedule a backup script at 2 AM every day:
0 2 * * * /home/username/backup.sh
Let’s break down what each field does:
0= minute 0 (the top of the hour)2= 2 AM* * *= every day, every month, every weekday/home/username/backup.sh= the script to run
Step 3: Save and Exit
In nano, press Ctrl+X, then Y, then Enter. In vim, type :wq and press Enter. You’ll see a message confirming the crontab was installed.
Step 4: Verify It’s Working
List your active cron jobs with:
crontab -l
You should see your newly created job. Now you wait—or set up a test job that runs every minute to verify everything works.
Real-World Cron Job Examples I Use Daily
Theory is great, but practical examples stick better. Here are cron jobs I actually run on production systems.
Run a Backup Every Night at 3:30 AM
30 3 * * * /usr/local/bin/database-backup.sh >> /var/log/backup.log 2>&1
The >> /var/log/backup.log 2>&1 part redirects both standard output and errors to a log file. This is crucial—cron jobs run silently, and without logging, you’ll never know if they fail.
Clear Temporary Files Every Hour
0 * * * * find /tmp -type f -mtime +7 -delete
This runs at the top of every hour, deleting files in /tmp older than 7 days. Simple maintenance that prevents disk space issues.
Send a Weekly Report Every Monday at 9 AM
0 9 * * 1 /home/admin/reports/weekly-stats.sh
The 1 in the weekday field means Monday. This ensures my team gets their stats report first thing Monday morning without me lifting a finger.
Monitor Server Health Every 5 Minutes
*/5 * * * * /usr/local/bin/health-check.sh
The */5 syntax runs the health check every 5 minutes. If something breaks, I know within 5 minutes instead of hours later when a customer complains.
For more advanced pattern matching when analyzing your health check logs, check out my guide on using the Linux grep command.
Common Cron Job Mistakes (And How to Avoid Them)
I’ve made every mistake possible with cron jobs over the years. Let me save you some pain by highlighting the biggest traps beginners fall into.
Mistake #1: Relative Paths Don’t Work
Your script runs perfectly from the command line but fails silently in cron. The problem? Cron doesn’t run from your home directory. It doesn’t inherit your shell’s environment variables or PATH.
Bad example:
0 2 * * * ./backup.sh
Good example:
0 2 * * * /home/username/scripts/backup.sh
Always use absolute paths for commands and scripts in cron jobs. If your script references other files or commands, use absolute paths inside the script too.
Mistake #2: Environment Variables Are Missing
Cron runs with a minimal environment. Your PATH is restricted to /usr/bin:/bin, and none of your custom variables from .bashrc or .bash_profile get loaded.
If your script needs specific environment variables, define them at the top of your crontab:
PATH=/usr/local/bin:/usr/bin:/bin MAILTO=admin@example.com 0 2 * * * /home/username/backup.sh
Or source them inside your script:
#!/bin/bash source /home/username/.env # rest of your script
Mistake #3: No Logging Means Silent Failures
Cron jobs fail silently. Unless you explicitly redirect output, you won’t know something broke until it’s too late.
Always redirect output to a log file:
0 2 * * * /home/username/backup.sh >> /var/log/backup.log 2>&1
The >> file.log appends standard output, and 2>&1 redirects errors to the same file. Now you can review logs to catch problems early.
Mistake #4: Accidentally Deleting Your Crontab
This one hurts. If you type crontab -r instead of crontab -e, your entire crontab gets deleted—no confirmation prompt, no undo button.
Before making changes, backup your crontab:
crontab -l > ~/crontab-backup-$(date +%Y%m%d).txt
I run this every Friday. It’s saved me twice.
Mistake #5: Overlapping Jobs
If a job scheduled to run every 10 minutes takes 15 minutes to complete, you’ll have multiple instances running simultaneously, competing for resources and potentially corrupting data.
Use file locks in your scripts to prevent overlapping execution, or consider using systemd timers instead of cron for complex jobs. For more details on managing services effectively, read my comparison of systemctl restart vs reload.
Special Cron Shortcuts for Common Schedules
Remembering that 0 0 * * 0 means “every Sunday at midnight” gets tedious. Linux offers shortcut keywords for common scheduling patterns.
These special strings replace the five time fields:
@reboot— Run once at startup@yearlyor@annually— Run once a year at midnight on January 1st@monthly— Run once a month at midnight on the first day@weekly— Run once a week at midnight on Sunday@dailyor@midnight— Run once a day at midnight@hourly— Run once an hour at the beginning of the hour
Here’s how you’d use them:
@daily /home/username/daily-backup.sh @reboot /usr/local/bin/startup-script.sh @weekly /home/username/reports/weekly-summary.sh
Much easier to read and understand at a glance.
Viewing and Managing Existing Cron Jobs
As your automation grows, you’ll need to manage multiple cron jobs. Here are the commands I use daily.
List Your Cron Jobs
crontab -l
This displays all cron jobs for your current user.
Edit Your Cron Jobs
crontab -e
Opens your crontab in your default editor.
Remove All Your Cron Jobs
crontab -r
Warning: This deletes your entire crontab without confirmation. Use with extreme caution.
View System-Wide Cron Jobs
User crontabs aren’t the only place cron jobs live. System administrators can place jobs in:
/etc/crontab— System-wide crontab file/etc/cron.d/— Directory for package-specific cron jobs/etc/cron.daily/,/etc/cron.weekly/,/etc/cron.monthly/— Scripts that run daily, weekly, or monthly
Check these locations if you’re troubleshooting unexpected system behavior.
When to Use Cron vs. Systemd Timers
Cron has been the standard for decades, but modern Linux distributions also offer systemd timers as an alternative. So which should you use?
Use cron when:
- You need simple, time-based scheduling
- You’re working across multiple systems (cron is more portable)
- You want something familiar that works everywhere
Use systemd timers when:
- You need event-based triggering (run after boot, after another service completes)
- You want built-in logging through
journalctl - You need dependency management between services
- You want to prevent overlapping job instances automatically
For most straightforward scheduling needs, cron works perfectly. I still use it for 90% of my scheduled tasks. But for complex service dependencies or mission-critical jobs, systemd timers offer advantages worth considering.
If you’re interested in exploring systemd further, read my detailed comparison of systemd timers vs cron.
Troubleshooting Cron Jobs That Won’t Run
Nothing is more frustrating than a cron job that should work but doesn’t. Here’s my systematic debugging process.
Step 1: Verify the Cron Service is Running
systemctl status cron
On some distributions, the service is called crond instead of cron. If it’s not running, start it:
sudo systemctl start cron sudo systemctl enable cron
Step 2: Check Your Syntax
Copy your cron expression to Crontab Guru and verify it schedules when you think it does. I’ve wasted hours debugging scripts only to discover my schedule was wrong.
Step 3: Test the Command Manually
Run your command directly from the shell as the cron user:
sudo -u username /path/to/script.sh
If it fails here, it’ll fail in cron too. Fix the command first.
Step 4: Check Permissions
Your script needs execute permissions. Verify with:
ls -l /path/to/script.sh
If it’s not executable, fix it with:
chmod +x /path/to/script.sh
For more details on file permissions, see my guide on the Linux chmod command.
Step 5: Review Logs
Check system logs for cron execution history:
grep CRON /var/log/syslog
Or on systemd systems:
journalctl -u cron
Look for your job and any error messages. The official cron troubleshooting guide from Cronitor covers edge cases I haven’t hit yet.
Step 6: Add Verbose Logging
Modify your cron job to capture all output:
*/5 * * * * /path/to/script.sh > /tmp/cron-debug.log 2>&1
Then check /tmp/cron-debug.log after the job should have run. This reveals environment issues, missing dependencies, and other problems invisible from the outside.
How Automating Tasks Changed My Workflow
Learning cron jobs genuinely transformed how I work. Tasks that used to require me logging in at specific times—database backups, certificate renewals, report generation—now happen automatically while I sleep.
That 2 AM database backup failure I mentioned at the beginning? It never happened again after I scheduled it as a cron job. The backup runs every night at 3:30 AM, logs succeed or fail status, and sends me an email if something breaks.
I’ve automated log rotation, disk space monitoring, security scans, and even my weekly coffee subscription order reminder (okay, that last one is personal, but it works).
The beautiful thing about automation is it compounds. Each task you automate frees up mental space and time for more important work. Just like dollar cost averaging automates your investing strategy, cron jobs automate your system administration.
Start small. Pick one repetitive task you do weekly and automate it this afternoon. Then find another next week. Six months from now, you’ll look back amazed at how much you’ve delegated to your silent robot assistant.
Your Next Steps with Cron
You now know how to schedule cron jobs in Linux, avoid common mistakes, and troubleshoot problems when they arise. The official crontab manual page provides exhaustive reference documentation when you need to go deeper.
Here’s what I recommend doing right now:
- Open your terminal and run
crontab -e - Create a simple test job that writes the current date to a file every minute
- Verify it works by checking the output file after a few minutes
- Once you’ve confirmed it works, remove the test and schedule something you actually need automated
The hardest part is starting. After you’ve created your first working cron job, the rest gets easier. Before long, you’ll be automating everything, wondering how you ever managed servers without it.
If you’re ready to expand your Linux automation toolkit, explore how to kill runaway processes that cron jobs occasionally spawn, or learn how to check which ports are open when your scheduled services start listening on the network.
Now go automate something. Your future self will thank you.







