
It’s a common situation. You schedule a backup for 2 a.m., but when you log in the next morning, the file isn’t there. Or perhaps a scheduled post missed its publication window, leaving you with a “Missed Schedule” error.
The root cause is often the WordPress cron system. Unlike a standard system cron that runs on a strict clock, WP-Cron is a pseudo-cron. It relies on page visits to trigger scheduled tasks. If no one visits the site, the tasks don’t run. If a visitor arrives while a heavy task is pending, their page load might hang while WordPress processes the queue in the background.
Debugging this via the WordPress dashboard is often frustrating. Installing a plugin just to view your cron events adds unnecessary bloat. A more direct and reliable method is to use the command line.
WP-CLI provides immediate visibility into the scheduler and, more importantly, allows you to force-run events to see if they fail.
Gaining Visibility
The first step in debugging is seeing what is actually in the queue. The default dashboard gives you no insight into this, but one command reveals the entire schedule.
Run the following command in your terminal:
wp cron event list
This outputs a table with four key columns: hook, next_run_gmt, next_run_relative, and recurrence.
The most important column for debugging is next_run_relative.
- If it says “10 minutes” or “1 hour,” the event is scheduled for the future.
- If it says “now”, “1 hour ago”, or “Yesterday”, the event is stuck.
A “stuck” event usually means one of two things: either the site hasn’t had any traffic to trigger the runner, or the PHP script attempted to run but crashed silently.
The Magic Fix: Force Running Events
Waiting for a suspect task to run naturally is inefficient. You need to see the error output immediately.
You can force any event to run right now, regardless of its schedule, using the run command:
wp cron event run <hook_name>
For example, if your backup hook is named my_daily_backup, you would run:
wp cron event run my_daily_backup
When WP-Cron runs normally (via a page visit), PHP errors are often suppressed or hidden in a log file you might not be checking. Fatal errors are output directly to your terminal hen you run it via WP-CLI.
If the script is running out of memory or hitting a PHP timeout, the command line will tell you instantly.
Clearing the Backlog
If you manage a site that has been offline or neglected, you might find dozens of overdue tasks clogging the queue. Rather than running them one by one, you can force WordPress to process all overdue events at once:
wp cron event run --due-now
Cleaning Up the Junk
Over time, the wp_options table can accumulate orphaned cron events. These are scheduled tasks left behind by plugins that were deactivated or deleted incorrectly. They don’t break the site, but they do clutter the database and the cron list.
To delete a specific event:
wp cron event delete <hook_name>
Be careful not to delete core WordPress hooks (like wp_scheduled_delete or wp_version_check). Focus only on hooks clearly named after plugins you no longer use.
Alternative: Disabling the Default WP-Cron
For high-traffic sites, or sites where timing is critical, relying on page visits to trigger tasks is often insufficient. In these cases, it’s common to disable the default behavior and replace it with a system cron.
This involves two steps. First, you disable the trigger in wp-config.php:
define('DISABLE_WP_CRON', true);
This stops WordPress from checking for scheduled tasks on every page load, which can improve page load speed for users.
However, once this is disabled, nothing will run until you set up an alternative trigger. You must add an entry to your server’s system crontab to call WP-CLI every minute.
Important: Do not run this as the root user. WP-CLI limits root execution for security reasons. Instead, add this line to the crontab of your web server user (often www-data) or your specific hosting user:
* * * * * /usr/local/bin/wp cron event run --due-now --path=/var/www/yoursite/ > /dev/null 2>&1
There are three key changes in this command compared to a standard manual run:
- Full Path: We use
/usr/local/bin/wpbecause system crons run in a minimal environment and might not know where thewpcommand is located otherwise. - Path to Site: The
--pathflag ensures WP-CLI executes within the correct WordPress installation. - Silencing Output: The
> /dev/null 2>&1at the end prevents the server from emailing you a notification every single minute that the task ran successfully.
This configuration ensures that scheduled tasks run precisely on time, regardless of whether anyone is visiting the website.
Conclusion
WP-Cron shouldn’t be viewed as a “black box” that developers cross their fingers and hope works. Shifting your workflow to the terminal turns that black box into a transparent queue. Using wp cron event list and run allows you to diagnose issues in seconds rather than days, ensuring your backups, emails, and scheduled posts happen exactly when they are supposed to.