Cron Expression Examples: Every 5 Minutes, Hourly, Daily
Chat2DB TeamCron is the de facto standard for scheduling recurring jobs on Unix-like systems, and its expression syntax has spread far beyond crontab: Kubernetes CronJobs, Spring @Scheduled, Jenkins, GitLab CI, pg_cron, and dozens of other tools all accept the same five-field format. This guide starts with the most searched-for schedule — the cron expression for every 5 minutes — and then works through the full syntax, a large table of copy-paste examples, the special strings, and the mistakes that silently break schedules.
The 5-Field Cron Format Explained
A standard cron expression has five fields, read left to right:
┌───────────── minute (0–59)
│ ┌───────────── hour (0–23)
│ │ ┌───────────── day of month (1–31)
│ │ │ ┌───────────── month (1–12 or JAN–DEC)
│ │ │ │ ┌───────────── day of week (0–7, 0 and 7 = Sunday, or SUN–SAT)
│ │ │ │ │
* * * * * command-to-runEach field accepts:
*— every value in the field's range ("any").- A single number — exactly that value (
30in the minute field means minute 30). - A list — comma-separated values:
0,15,30,45. - A range —
9-17means 9 through 17 inclusive. - A step —
*/5means "every 5th value starting from the range minimum";10-50/10means 10, 20, 30, 40, 50.
The answer to the headline question: the cron expression for every 5 minutes is */5 * * * *. It fires at minutes 0, 5, 10, ..., 55 of every hour, every day.
# Run a health check every 5 minutes
*/5 * * * * /usr/local/bin/healthcheck.sh >> /var/log/healthcheck.log 2>&1Note that */5 is equivalent to 0-59/5, so the first run of each hour is always at minute 0. If you need "every 5 minutes starting at minute 2", write 2-59/5 instead (2, 7, 12, ..., 57).
Copy-Paste Cron Expression Table
All of these are standard 5-field expressions and work in crontab, Kubernetes, pg_cron, and most schedulers.
| Schedule | Expression | Fires at |
|---|---|---|
| Every minute | * * * * * | :00, :01, :02, ... |
| Every 5 minutes | */5 * * * * | :00, :05, :10, ... |
| Every 10 minutes | */10 * * * * | :00, :10, :20, ... |
| Every 15 minutes | */15 * * * * | :00, :15, :30, :45 |
| Every 30 minutes | */30 * * * * | :00, :30 |
| Every hour, on the hour | 0 * * * * | 00:00, 01:00, 02:00, ... |
| Every 2 hours | 0 */2 * * * | 00:00, 02:00, 04:00, ... |
| Every 6 hours | 0 */6 * * * | 00:00, 06:00, 12:00, 18:00 |
| Daily at midnight | 0 0 * * * | 00:00 every day |
| Daily at 2:00 AM | 0 2 * * * | 02:00 every day |
| Daily at 2:30 AM | 30 2 * * * | 02:30 every day |
| Twice daily | 0 6,18 * * * | 06:00 and 18:00 |
| Weekdays at 9:00 AM | 0 9 * * 1-5 | Mon–Fri 09:00 |
| Weekdays every 15 min, 9–17 | */15 9-17 * * 1-5 | Business hours only |
| Weekly (Sunday midnight) | 0 0 * * 0 | Sun 00:00 |
| Weekly (Monday 8 AM) | 0 8 * * 1 | Mon 08:00 |
| Monthly (1st, midnight) | 0 0 1 * * | 1st of month 00:00 |
| Monthly (15th, 6 AM) | 0 6 15 * * | 15th of month 06:00 |
| Quarterly | 0 0 1 1,4,7,10 * | Jan/Apr/Jul/Oct 1st |
| Quarterly (step form) | 0 0 1 */3 * | Same as above |
| Yearly (Jan 1, midnight) | 0 0 1 1 * | Once per year |
| Every Sat and Sun at noon | 0 12 * * 6,0 | Weekend 12:00 |
A worked example combining ranges, lists, and steps:
# Minutes 0 and 30, between 08:00 and 18:59, Mon/Wed/Fri, March through November
0,30 8-18 * 3-11 1,3,5 /opt/scripts/sync-reports.shSpecial Strings: @daily, @hourly, @reboot
Most cron implementations (Vixie cron, cronie, and derivatives) accept shorthand macros in place of the five fields:
| String | Equivalent | Meaning |
|---|---|---|
@hourly | 0 * * * * | Once an hour, on the hour |
@daily / @midnight | 0 0 * * * | Once a day at 00:00 |
@weekly | 0 0 * * 0 | Sundays at 00:00 |
@monthly | 0 0 1 * * | 1st of month at 00:00 |
@yearly / @annually | 0 0 1 1 * | Jan 1 at 00:00 |
@reboot | (none) | Once, when the daemon starts |
@reboot has no five-field equivalent — it triggers when the cron daemon starts, typically at system boot. It is handy for starting user-level services without systemd units:
# crontab -e
@reboot /home/deploy/bin/start-tunnel.shBe careful: @reboot also fires if the cron service is restarted (for example after systemctl restart cron on some distributions), and not all environments — notably Kubernetes CronJobs — support the @ macros at all.
Steps, Ranges, and Lists in Detail
Three composition rules cover almost everything:
- Steps apply to a range.
*/5in the minute field means0-59/5.1-10/3means 1, 4, 7, 10. A step on a bare number (5/10) is non-standard; some implementations accept it (meaning "start at 5, every 10"), classic cron does not. - Lists can contain ranges.
0-4,20-24 * * * *runs at minutes 0–4 and 20–24. Some implementations also allow steps inside list items:0-29/10,45. - Names are allowed in month and day-of-week.
0 9 * JAN-MAR MON-FRIis valid in most modern crons, but ranges of names are not portable everywhere — numeric forms are the safest choice for portability.
One important limitation: steps cannot express intervals that do not divide the field range evenly. */40 in the minute field fires at :00 and :40 of every hour — not "every 40 minutes". For true 40-minute (or 90-minute) intervals you need multiple cron lines or a different scheduler.
Common Mistakes
0 vs * in the minute field
The single most common cron bug:
# WRONG: runs every minute between 02:00 and 02:59 (60 runs)
* 2 * * * /opt/scripts/backup.sh
# RIGHT: runs once at 02:00
0 2 * * * /opt/scripts/backup.shAn * in the minute field means "every minute during whichever hours match". Whenever you pin the hour, pin the minute too.
Day-of-month vs day-of-week is OR, not AND
When both the day-of-month and day-of-week fields are restricted (neither is *), classic cron runs the job when either matches:
# Intended: "Friday the 13th". Actual: every Friday AND every 13th of the month.
0 0 13 * 5 /opt/scripts/spooky.shThis OR semantic surprises nearly everyone. To get a true AND, keep one field as * and test the other condition inside the command:
# Runs on the 13th; the date check keeps only Fridays
0 0 13 * * [ "$(date +\%u)" -eq 5 ] && /opt/scripts/spooky.sh(Note the escaped % — in a crontab file a literal percent sign must be written \%, because unescaped % marks the start of stdin data for the command.)
Timezone issues
Classic crontab evaluates expressions in the system timezone of the machine (or the TZ/CRON_TZ variable where supported). Problems to watch for:
- Servers in UTC.
0 9 * * 1-5on a UTC server fires at 09:00 UTC, which is 02:00 in Los Angeles and 17:00 in Beijing. Decide deliberately which timezone you mean. - DST transitions. Jobs scheduled between 02:00 and 03:00 local time may be skipped (spring forward) or run twice (fall back) depending on the implementation. Schedule critical nightly jobs outside the DST transition window — 03:30 or later is safe in most jurisdictions.
- Mixed fleets. If some servers run local time and some run UTC, identical crontab lines fire hours apart. Standardize on UTC for infrastructure jobs.
You can sanity-check any expression, see its next fire times in plain English, and generate new ones with the free cron expression generator (opens in a new tab).
Environment differences
Cron runs commands with a minimal environment: PATH is typically just /usr/bin:/bin, and your shell profile is not sourced. Always use absolute paths for binaries and files, or set PATH at the top of the crontab.
Scheduling Inside the Database
PostgreSQL with pg_cron
pg_cron runs cron-format schedules inside PostgreSQL itself, which is ideal for maintenance SQL — partition rotation, materialized view refreshes, data retention.
-- One-time setup (postgresql.conf): shared_preload_libraries = 'pg_cron'
CREATE EXTENSION pg_cron;
-- Refresh a materialized view every 5 minutes
SELECT cron.schedule(
'refresh-dashboard-mv',
'*/5 * * * *',
$$REFRESH MATERIALIZED VIEW CONCURRENTLY dashboard_stats$$
);
-- Purge rows older than 90 days, daily at 03:30
SELECT cron.schedule(
'purge-old-events',
'30 3 * * *',
$$DELETE FROM events WHERE created_at < now() - interval '90 days'$$
);
-- Inspect and manage jobs
SELECT jobid, jobname, schedule, command FROM cron.job;
SELECT * FROM cron.job_run_details ORDER BY start_time DESC LIMIT 10;
SELECT cron.unschedule('purge-old-events');pg_cron evaluates schedules in the server's configured timezone (GMT by default in many managed offerings), so verify with SHOW timezone; before assuming local time.
MySQL Event Scheduler
MySQL has a built-in scheduler that uses EVERY ... INTERVAL syntax rather than cron fields, but it covers the same use cases:
-- Make sure the scheduler is on
SET GLOBAL event_scheduler = ON;
-- Equivalent of */5 * * * * : run every 5 minutes
CREATE EVENT rollup_metrics_5min
ON SCHEDULE EVERY 5 MINUTE
STARTS CURRENT_TIMESTAMP
DO
INSERT INTO metrics_5min (bucket, cnt)
SELECT NOW(), COUNT(*) FROM raw_events
WHERE created_at >= NOW() - INTERVAL 5 MINUTE;
-- Equivalent of 0 2 * * * : daily at 02:00
CREATE EVENT nightly_cleanup
ON SCHEDULE EVERY 1 DAY
STARTS (TIMESTAMP(CURRENT_DATE) + INTERVAL 1 DAY + INTERVAL 2 HOUR)
DO
DELETE FROM sessions WHERE last_seen < NOW() - INTERVAL 30 DAY;
-- Inspect scheduled events
SHOW EVENTS;The STARTS clause anchors the phase: EVERY 1 DAY STARTS ... + INTERVAL 2 HOUR means "daily at 02:00" rather than "daily at whatever time the event was created". Before scheduling any of this SQL, it pays to run and profile it interactively — a tool like Chat2DB (opens in a new tab) lets you connect to PostgreSQL or MySQL, test the exact statement a job will execute, and check its execution plan before you hand it to a scheduler that runs it unattended at 3 AM.
FAQ
What is the cron expression for every 5 minutes?
*/5 * * * *. It runs at minutes 0, 5, 10, ..., 55 of every hour.
How do I run a job every day at midnight?
0 0 * * *, or the shorthand @daily.
Why does my job run 60 times instead of once?
You likely left * in the minute field, e.g. * 2 * * *. Change it to 0 2 * * *.
Does cron support seconds?
Standard 5-field cron does not. Quartz (Java) and some frameworks use a 6- or 7-field format with a leading seconds field — 0 */5 * * * ? in Quartz equals */5 * * * * in standard cron. Never paste Quartz expressions into crontab or vice versa.
Can two restricted day fields ever mean AND?
In classic cron, no — restricted day-of-month and day-of-week combine with OR. Quartz sidesteps the ambiguity by requiring ? in one of the two fields.
