Skip to main content

WP-Cron Not Working: Moving Tasks to System Cron

WordPress · 29.09.2026

WP-Cron in WordPress does not run on an operating-system schedule; it fires when a visitor loads the site: the wp-cron.php file is pinged on every page load and checks whether a scheduled task is due. On a site with rare visits, scheduled publishing and mailings run hours late. Here is how to fix that with the system cron.

Why WP-Cron is late or does not fire at all

The WordPress pseudo-cron lives only while there is traffic: no visit means no task check. A second cause of failures is shared hosting with aggressive page caching: a caching plugin serves a stored HTML copy and never lets the request reach PHP, and therefore never reaches wp-cron.php. A third cause is an outbound self-request blocked at the server level, which stops WordPress from pinging itself over HTTP.

How to check the current state of tasks

The list of scheduled tasks and their exact time is easy to check through WP-CLI, if it is available on the hosting.

wp cron event list --fields=hook,next_run_relative,recurrence

If the next_run_relative column shows a negative value like "-3 hours", the task is overdue and is waiting for the next visitor to arrive so it can run.

How to disable the built-in pseudo-cron

Disabling it takes one constant in wp-config.php — add the line before the "That's all, stop editing!" marker.

<?php
define('DISABLE_WP_CRON', true);

After this change, WordPress stops checking tasks on every visit, but the tasks themselves stay in the database — their run simply waits for an outside trigger.

How to set up system cron instead of the pseudo-cron

The task must be handed to the operating system's own scheduler. Add a line through crontab -e under the user account the site runs as.

*/5 * * * * curl -s https://site.example/wp-cron.php?doing_wp_cron >/dev/null 2>&1

Running every 5 minutes is a reasonable compromise for most sites: mailings and scheduled posts do not run noticeably late, and server load stays low. If WP-CLI is available on the server, calling it directly is more reliable — it skips the HTTP layer and does not depend on page cache.

*/5 * * * * cd /var/www/site.example/public_html && wp cron event run --due-now --quiet

How to choose an interval for different tasks

TaskRecommended intervalEffect of being late
Scheduled post publishing1-5 minutescontent goes live later than planned
Scheduled email mailing5 minutesemails go out in a delayed batch
Plugin temp data cleanup15-30 minutesdatabase size grows
Core and plugin update checks1 time per hourupdate notice is delayed

Common mistakes when moving to system cron

A forgotten DISABLE_WP_CRON constant causes duplication: tasks run both on the system schedule and on the old pseudo-cron during a visit, so mailing emails can go out twice. A second mistake is having cron set up on the server while the site still runs LiteSpeed Cache or a similar plugin that caches wp-cron.php itself as a plain page — exclude this path from the cache rules explicitly. A full list of steps for a domain change and the related cron migration tasks is in the article about changing a WordPress domain.

Checking that the move worked is simple: an hour after setting up system cron, run wp cron event list again and confirm the next_run_relative column keeps moving forward even without site visits. Other commands are useful for managing and diagnosing tasks too — a set of them is collected in the article about WP-CLI.

Summary

  • WP-Cron by default fires only on a visitor's request, so tasks run late on quiet sites.
  • The pseudo-cron can be disabled with the DISABLE_WP_CRON constant in wp-config.php.
  • The task must be handed to the operating system's crontab with a 5-minute interval via curl or directly through WP-CLI.
  • After the move, check that tasks are not running twice because of a forgotten constant.
  • Caching plugins should be configured so they never serve wp-cron.php from cache.
← Back to Knowledge Base Ask Support