Cron every 2 hours: 0 */2 * * * and the mistakes that break it

By TechCompare · Updated · How we check

0 */2 * * * is the right line for a job every two hours, as long as the server clock is the one you expect. Keep the leading zero, and check the hour step if the gaps matter.

Calculator

Next runs of 0 */2 * * *

Example from Mon, Nov 9, 2026 at 8:00 AM.

  1. Mon, Nov 9, 2026 at 10:00 AM
  2. Mon, Nov 9, 2026 at 12:00 PM
  3. Mon, Nov 9, 2026 at 2:00 PM
  4. Mon, Nov 9, 2026 at 4:00 PM
  5. Mon, Nov 9, 2026 at 6:00 PM

0 */2 * * * runs a job at the top of every second hour, starting at midnight. The 0 pins the minute to :00, and */2 in the hour field picks the even hours. That's 12 runs a day. It's a short line, which makes its slips easy to miss. This page covers those slips and how to get odd hours instead.

Schedule pattern
Every 2 hours
every-2-hours
Category
Common Patterns
Standard cron expression patterns

How this is calculated

Here's how the fields read. The minute field is 0, so every run lands at :00. The hour field is */2, which picks each hour that's a multiple of 2, counted from midnight: 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22. The last three fields are *, so the job runs every day, in every month, on every weekday. A crontab line with a real command looks like this:

crontab
0 */2 * * * /usr/local/bin/refresh-cache

The first slip is dropping the leading zero. Write * */2 * * * and the minute field matches every minute, so the job fires once a minute during each even hour. The line still looks almost right, which is why it gets past a quick read. That's 720 runs a day, against 12 with the zero in place, so the broken version floods the log if the job writes any output. The fix is to put the 0 back in front.

The second trap is the hour step. Cron counts steps inside each field, and crontab(5) says "steps are evaluated just within the field they are applied to." So */2 starts over at midnight every day. A step of two divides 24 evenly, so every gap matches the step and the schedule looks right. A step like */5 doesn't divide 24 evenly. It runs at hours 0, 5, 10, 15, 20 each day. The gap from the last of those hours to midnight is shorter than the rest, so a job that needs even spacing will run at uneven intervals. If that gap matters, use a step that divides 24, like */6, which gives hours 0, 6, 12, 18.

Odd hours need a different expression, since */2 only ever lands on even hours. If you want them, like the 1 AM run and the 3 AM run, write 0 1-23/2 * * *. That runs at hours 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, and that's 12 runs a day. It's a handy offset when a second job should use the other hours. Midnight doesn't cause a short gap here, since the odd hours wrap around at the same spacing.

Hours are read on the server's clock. Cron uses the server's local time zone by default, so the even hours are even only on that clock. If the server runs in UTC but your team sits in a zone an odd number of whole hours away, the even UTC hours are odd hours on the team's clock, and the job runs at hours the team didn't plan for. Where your cron supports CRON_TZ, set it above the job line, or convert the hours to UTC by hand. The full story is on the time zone page.

Compare it with its neighbors before you pick it. An hourly job (0 * * * *) runs more often than this one, so pick it only for data that goes stale within the hour. This schedule runs more often than 0 */6 * * *, which runs 4 times a day and suits a report or a sync that can wait a few hours.

Verdict

Before you save, read the minute field, then the hour step, then the server's clock. A * in the minute field changes how often the job fires, and a step like */5 leaves a short gap before midnight. For odd hours, write 1-23/2 on purpose and add a comment above the line so nobody changes it back by mistake.

More Cron scenarios

Every 5 minutes
Running a cron job every 5 minutes uses the step operator in the minute field: */5 * * * *.
View details
Every hour
To run a job at the top of every hour, use 0 * * * *.
View details
Daily at midnight
0 0 * * * runs a job at exactly midnight (00:00) every day.
View details

Frequently asked questions

How do I run a cron job every 2 hours?
Use 0 */2 * * * in your crontab. The 0 runs the job at :00, and */2 in the hour field picks every second hour, so the job runs at hours 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22. That's 12 runs a day.
Why does my cron job run every minute when it should run every 2 hours?
The minute field is * instead of 0, which means every minute counts, not just :00. Run crontab -l to see the line that's saved, and check that the first field reads 0.
How do I run a job every 2 hours starting at 1 AM?
Use 0 1-23/2 * * *. The hour field 1-23/2 picks every other hour starting at 1, so the job runs at hours 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23 and the cycle starts again at 1 AM. That's 12 runs a day.
Is every 2 hours in cron the same as listing each even hour?
Yes. 0 */2 * * * is shorthand for an explicit list. Written out, the hour field is 0,2,4,6,8,10,12,14,16,18,20,22, so the full line is 0 0,2,4,6,8,10,12,14,16,18,20,22 * * *. Keep the commas and drop the spaces, since cron reads a space as the end of a field.
What happens if I put */5 in the hour field?
The job still runs every day, at hours 0, 5, 10, 15, 20, and cron doesn't throw an error. The problem is spacing. Cron evaluates steps within the field, as crontab(5) describes, so the step starts over at midnight and the gap before midnight comes out short. If the job needs even spacing, use a step that divides 24, like */6, or list the hours you want.