WordPress cron is not actually cron
On a real server, a cron job runs on a fixed schedule. Every 5 minutes, every hour, every day at midnight — the server wakes up and executes the task regardless of what else is happening. It does not depend on anyone visiting a website. It does not depend on traffic. It just runs.
WordPress wp-cron does not work this way. It has no scheduler. It has no background process. It cannot wake itself up. Instead, every time a visitor loads any page on your WordPress site, WordPress runs a quick check: are there any scheduled tasks that are overdue? If yes, it fires them. If no visitor comes, no check happens. No check, no tasks run. It is that simple and that broken.
This design made sense in 2004 when WordPress was a blogging platform running on shared hosting where server-level cron access was rare. It does not make sense in 2026 when WordPress powers business-critical sites, ecommerce stores, and SaaS applications where scheduled tasks are not optional. But the architecture has not changed. WordPress still depends on a visitor walking through the door before it checks its to-do list.
If your site gets steady traffic — a visitor every few minutes — wp-cron works well enough. Tasks fire close to their scheduled time. The delay is a few minutes at most. But if your site has low traffic — a small business site, a staging environment, a site behind a password, a new site that has not been indexed yet — hours can pass between visits. During those hours, every scheduled task sits idle. Your 9am post publishes at 2pm when someone finally visits. Your daily backup runs three days late. Your security scan never triggers.
Everything that breaks when wp-cron stops firing
The damage from a non-firing wp-cron is not dramatic. There is no error page, no crash, no alert. Things just quietly stop happening. And because they stop silently, you often do not notice for days or weeks.
Scheduled posts publish late or not at all
WordPress's scheduled publishing feature relies entirely on wp-cron. When you schedule a post for 9am, WordPress stores the post with a "future" status and a timestamp. The next time wp-cron runs after 9am, it checks for posts with a past-due timestamp and publishes them. If wp-cron does not run until 3pm, the post publishes at 3pm. If your site gets no traffic that day, the post never publishes at all — it stays in "Scheduled" status indefinitely. This is the classic "missed schedule" problem that frustrates WordPress users who manage editorial calendars.
Backup plugins miss their schedule
Plugins like UpdraftPlus, BackWPup, and BlogVault schedule backups through wp-cron. If you configured daily backups at 2am, the backup only runs when the first visitor arrives after 2am. On a site with no overnight traffic, that might be 8am. On a very low-traffic site, it might be the next afternoon. Or it might not run that day at all. Your "daily backup" becomes a weekly backup — and you do not find out until you need to restore from one that does not exist.
Email notifications silently stop
Many plugins use wp-cron to send scheduled emails — digest summaries, weekly reports, membership renewal reminders, WooCommerce follow-up emails, and subscription notifications. When wp-cron does not fire, these emails sit in the queue indefinitely. Your customers do not get their order status updates. Your subscribers do not get their weekly digest. Your members do not get their renewal reminders. There is no error — the emails are queued and waiting. They just never get processed.
Database maintenance stops
WordPress schedules internal maintenance tasks through wp-cron: deleting expired transients, cleaning up revision history, checking for core and plugin updates, and rotating log files. When these stop running, your database grows with stale data, your wp_options table fills with expired transients, and you miss security updates because the update check never fires. The site slows down gradually as the unmaintained database becomes bloated.
Security scans never trigger
Security plugins like Wordfence, Sucuri, and iThemes Security schedule regular malware scans through wp-cron. If wp-cron does not fire, the scans do not run. You think your site is being monitored. It is not. A malware infection could sit on your site for weeks before the next scan finally happens — if it happens at all.
The DISABLE_WP_CRON trap
Search for "WordPress slow" or "WordPress performance optimization" and half the guides will tell you to add this line to your wp-config.php:
define('DISABLE_WP_CRON', true);
The advice is not wrong. Running wp-cron on every page load does add overhead. On high-traffic sites, it can cause performance issues when multiple simultaneous requests all try to run cron tasks at the same time. Disabling the page-load trigger and replacing it with a server-level cron job is genuinely the recommended approach.
The problem is that most guides skip the second part. They tell you to disable wp-cron. They do not tell you — or do not emphasize enough — that you must set up a real cron job to replace it. Without the replacement, you have disabled the only mechanism that triggers scheduled tasks. Everything stops. Silently.
This is one of the most common WordPress misconfigurations. A developer or hosting guide tells you to disable wp-cron for performance. You add the line to wp-config.php. Your site feels faster (or you imagine it does). Weeks later, you notice your scheduled posts are not publishing. Your backups have not run. You have no idea the two are connected because you added that line to wp-config.php a month ago and forgot about it.
wp-cron.php errors that kill cron silently
Even when wp-cron is not disabled, it can fail silently due to errors in the wp-cron.php file itself.
Hosting blocks wp-cron.php
Some hosting providers block direct access to wp-cron.php because it can be abused for DDoS amplification attacks. Bots hit wp-cron.php repeatedly, causing the server to execute resource-intensive cron tasks on every request. The host blocks the file to protect server resources. But this also prevents legitimate cron execution. If your server-level cron job calls wp-cron.php via HTTP and the host returns a 403 or 404, cron silently fails. Check by visiting https://yourdomain.com/wp-cron.php?doing_wp_cron in your browser. If you get a blank page, it is working. If you get an error, it is blocked.
SSL/HTTPS misconfiguration
If your site uses HTTPS but the cron call uses HTTP (or vice versa), the request may fail due to redirect loops or SSL errors. This commonly happens when a site is migrated to HTTPS but the server-level cron job still uses the old HTTP URL. The HTTP request redirects to HTTPS, but the redirect does not carry the cron parameters, so wp-cron.php does not execute. The cron job appears to succeed (it got a 301 response) but the cron tasks never actually run.
PHP errors in cron callbacks
If a scheduled task contains a PHP error — a fatal error in a plugin's cron callback function — it can prevent other cron tasks from running in the same batch. WordPress processes cron tasks sequentially. If one task causes a fatal error, PHP execution stops and any remaining tasks in the queue are skipped. The site continues to work for visitors because the fatal error only occurs within the cron context, not during normal page loads.
How to fix wp-cron properly
Option 1: Server-level cron job (if you have SSH access)
This is the recommended approach. Disable the traffic-based trigger and replace it with a real cron job.
First, add to wp-config.php:
define('DISABLE_WP_CRON', true);
Then set up a cron job via crontab -e:
*/5 * * * * wget -q -O /dev/null https://yourdomain.com/wp-cron.php?doing_wp_cron
This pings wp-cron.php every 5 minutes regardless of traffic. Adjust the interval based on your needs — every minute for sites with time-sensitive tasks, every 15 minutes for sites where a few minutes of delay is acceptable. The WordPress Plugin Handbook cron documentation covers the details of wp-cron internals.
Option 2: WP-CLI cron runner (for VPS and dedicated servers)
If WP-CLI is installed on your server, you can trigger cron directly through the command line without making an HTTP request:
*/5 * * * * cd /path/to/wordpress && wp cron event run --due-now
This is more efficient than the HTTP approach because it does not create a web request — it runs PHP directly. It also avoids issues with blocked wp-cron.php URLs, SSL misconfigurations, and HTTP authentication.
Option 3: External cron trigger (for managed hosting without SSH)
If your hosting does not provide crontab access — which is common on managed WordPress hosts and shared hosting — you need an external service to ping wp-cron.php on a schedule. This is where Uptrue's heartbeat monitoring provides a dual benefit: it triggers your cron tasks on a fixed schedule and monitors that wp-cron.php is responding correctly.
How Uptrue heartbeat monitoring keeps wp-cron firing
Uptrue's heartbeat monitoring was designed to monitor scheduled tasks — but it works equally well as a cron trigger. By pointing a heartbeat monitor at your wp-cron.php URL, every ping serves double duty: it triggers WordPress to process any due cron tasks, and it monitors that wp-cron.php is responding correctly.
Step 1: Disable the built-in wp-cron trigger
Add to your wp-config.php (before the line that says "That's all, stop editing!"):
define('DISABLE_WP_CRON', true);
This stops WordPress from running wp-cron on every page load, which improves page load performance and prevents race conditions where multiple simultaneous visitors trigger cron at the same time.
Step 2: Set up an Uptrue heartbeat monitor
- Sign up at uptrue.io/signup (free plan available)
- Click Add Monitor from your dashboard
- Select Heartbeat as the monitor type
- Enter the URL:
https://yourdomain.com/wp-cron.php?doing_wp_cron - Set the check interval to 5 minutes (or 1 minute for time-critical tasks)
- Configure alerts — Slack, email, or Microsoft Teams
Every 5 minutes, Uptrue pings your wp-cron.php URL. This triggers WordPress to check for and execute any due scheduled tasks. If wp-cron.php returns an error — a 403 because hosting blocked it, a 500 because a plugin crashed, or a timeout because the server is overloaded — Uptrue alerts you immediately. You know the moment your scheduled tasks stop working.
Step 3: Add an HTTP monitor for your homepage
- Click Add Monitor again
- Select HTTP/HTTPS as the monitor type
- Enter your homepage URL
- Set expected status to 200
- Set the interval to 1 minute
This gives you full visibility: the heartbeat monitor ensures wp-cron fires and alerts you if wp-cron.php breaks, while the HTTP monitor ensures your site is up and serving visitors correctly. Together, they cover both the public-facing site and the background task infrastructure.
Step 4: Monitor the outcomes of critical cron tasks
Triggering wp-cron is only half the battle. You also need to verify that the tasks it runs are succeeding. Set up keyword monitors for the outcomes:
- Scheduled posts: Monitor your blog page for the title of a post that should have published — if it is missing, the cron task failed
- Backup plugins: Check your backup destination (cloud storage, email) for recent backup files
- Email digests: Subscribe to your own digest and monitor your inbox
Step 5: Configure alerts for cron failures
A broken cron is a silent failure. You will not notice until something important does not happen — a missed backup before a migration, a security scan that never ran before an infection, a renewal email that never sent before a membership lapsed. Get alerts the moment cron stops responding.
- Slack — instant notification when wp-cron.php returns an error
- Microsoft Teams — visibility for the entire ops team
- Email — written record of every cron failure
- Webhook — trigger automated remediation workflows
Check your WordPress site health right now
Instant health score across uptime, SSL, DNS, security headers, and performance. See if your scheduled tasks are at risk.
Check Your Website ScoreCommon wp-cron problems and quick fixes
Missed schedule error on posts
If posts show "Missed schedule" in wp-admin, wp-cron is not firing frequently enough. Either increase your site traffic, set up a server-level cron job, or use Uptrue heartbeat monitoring to ping wp-cron.php on a fixed schedule. There is also a Missed Schedule plugin that retries publishing missed posts, but it still depends on wp-cron firing — it does not fix the underlying trigger problem.
WP-Cron running too frequently on high-traffic sites
On high-traffic sites, every page load triggers wp-cron. Hundreds of simultaneous requests all try to run cron at the same time. This causes database locks, slow page loads, and resource spikes. The fix is to disable the page-load trigger with DISABLE_WP_CRON and use a server-level cron job or Uptrue heartbeat monitor instead. One request every 5 minutes is far more efficient than hundreds of requests per minute all checking the cron queue.
Cron tasks piling up and never completing
If a cron task takes longer than the PHP max_execution_time, it is killed before it finishes. The task stays in the queue and is retried on the next cron run — where it is killed again. Tasks pile up indefinitely. Check for plugins scheduling resource-intensive operations as single cron events. The fix is either to increase max_execution_time for cron context or to break the heavy task into smaller batches that complete within the time limit. The WordPress developer documentation on cron explains how to hook wp-cron into the system task scheduler properly.
Cron working locally but not on production
If cron works in your local development environment but not on your production server, the issue is almost always one of: production hosting blocks wp-cron.php (check for 403 or 404 responses), a security plugin blocks the cron request (check firewall rules), or HTTPS misconfiguration causes the cron HTTP request to fail silently. Test by visiting https://yourdomain.com/wp-cron.php?doing_wp_cron directly in your browser. If you get a blank white page, it is working. Any other response indicates a configuration problem.
Your scheduled tasks are probably not running right now
That is not hyperbole. If you run a low-traffic WordPress site — and most WordPress sites are low-traffic — your wp-cron is unreliable. Your scheduled posts publish hours late. Your backups are days behind schedule. Your security scans run sporadically at best. And you have no idea because wp-cron fails silently. There is no error message. There is no alert. Things just do not happen.
Uptrue heartbeat monitoring pings your wp-cron.php every few minutes on a fixed schedule. Every ping triggers WordPress to process due tasks. Every ping also verifies that wp-cron.php is responding. If it stops responding — because hosting blocked it, a plugin crashed it, or the server is down — you know in under five minutes. Your cron fires reliably. Your scheduled tasks run on time. And you get alerted the moment something breaks.
Keep your WordPress cron firing reliably
Free plan available. Heartbeat monitoring that triggers wp-cron on a fixed schedule and alerts you if it stops responding. No credit card required.
Frequently asked questions
Why is WordPress wp-cron not working?
WordPress wp-cron is not a real cron system. It does not run on a schedule. Instead, it checks for due tasks every time a visitor loads a page. If nobody visits your site for hours, no cron tasks run during those hours. Scheduled posts publish late, backup plugins miss their schedule, email digests never send, and maintenance tasks like database cleanup stop happening. Low-traffic sites, staging environments, and password-protected sites are especially affected because they do not receive enough page loads to trigger wp-cron reliably.
What happens if I set DISABLE_WP_CRON without a replacement?
If you add define("DISABLE_WP_CRON", true) to wp-config.php without setting up a real server cron job to call wp-cron.php, all scheduled tasks stop completely. No scheduled posts will publish. No backup plugins will run. No email notifications will send. No database maintenance will happen. No security scans will trigger. Many WordPress guides recommend disabling wp-cron for performance reasons but fail to explain that you must replace it with a server-level cron job or external trigger. Without the replacement, everything that depends on scheduling silently breaks.
Can uptime monitoring fix WordPress cron problems?
Yes, indirectly. Uptrue heartbeat monitoring can be configured to ping your wp-cron.php URL on a fixed schedule — every 1, 5, or 15 minutes. Each ping triggers WordPress to check for and execute any due cron tasks. This effectively turns the unreliable traffic-based wp-cron into a reliable schedule-based system. Combined with DISABLE_WP_CRON in wp-config.php, this gives you full control over when cron runs without relying on visitor traffic.
How do I set up a real cron job for WordPress?
First, add define("DISABLE_WP_CRON", true) to your wp-config.php to disable the traffic-based trigger. Then set up a server-level cron job that calls wp-cron.php on a fixed schedule. On Linux servers, use crontab: */5 * * * * wget -q -O /dev/null https://yourdomain.com/wp-cron.php?doing_wp_cron. On managed hosting without crontab access, use an external service like Uptrue heartbeat monitoring to ping wp-cron.php every few minutes. The external ping triggers WordPress to process all due scheduled tasks.