WP-Cron has a reputation for dragging WordPress performance down. Search any WordPress optimization guide and you'll find "disable wp-cron" somewhere in the checklist, right between "install a caching plugin" and "use a CDN." The advice isn't wrong, but the reasoning behind it usually is.
The performance hit from WP-Cron is real but small. On most sites, it adds roughly 18 milliseconds to a page load, about 1% of total response time. The actual problem is architectural: WP-Cron depends on visitors to trigger it, and that dependency breaks in ways that have nothing to do with speed.
Below: how both systems work, what the performance difference actually looks like with numbers, and when switching to server cron makes a real difference for your site.
Two systems, one job
Both WP-Cron and server cron exist to do the same thing: run tasks on a schedule. Publishing posts at a set time, processing WooCommerce orders, clearing expired transients, running backups. The difference is in how they decide when to check whether something needs to run.
WP-Cron: triggered by visitors
Every time someone loads a page on your WordPress site, PHP executes a function called wp_cron() at the end of the request. That function checks a list of scheduled events stored in the wp_options table. If anything is overdue, WordPress fires off a background HTTP request to wp-cron.php, which processes the queue. The visitor never sees this. Their page loads normally while the cron tasks run in a separate process.
The key phrase: "every time someone loads a page." No visitors, no check. Your 3 AM backup doesn't run at 3 AM if nobody visits the site between midnight and morning. It runs whenever the first visitor shows up. (We covered this in detail in our WP-Cron troubleshooting guide.)
Server cron: triggered by a clock
Linux, macOS, and most Unix-like operating systems include a daemon called crond that wakes up every minute, reads a schedule file (the crontab), and runs whatever is due. It doesn't care about visitors, traffic, or page loads. If the crontab says "run at 3:00 AM," it runs at 3:00 AM. The clock is the trigger, not a human.
For WordPress, server cron usually means adding a line to the crontab that hits wp-cron.php or runs a WP-CLI command on a fixed interval. WordPress still manages the event queue. The trigger just comes from the system clock instead of page loads. (For background on how crontab syntax works, see the complete cron job guide.)
The performance question, with numbers
Most "disable WP-Cron for performance" articles claim dramatic speedups but don't measure anything. Here's what the numbers actually show.
On an idle page load (no overdue events), the wp_cron() check reads one row from the wp_options table, compares a timestamp, and returns. That takes about 18 milliseconds. On a typical page load of 1.5 seconds, that's 1.2% of total response time. Not zero, but not the bottleneck your optimization guide makes it sound like.
On loaded servers the picture changes. When MySQL is under pressure from other queries, that single option lookup can take 50 to 200 milliseconds. If your server runs object caching with Redis or Memcached, the same lookup drops below 1 millisecond because it never hits the database at all.
The real performance cost comes when WP-Cron actually fires a background request. WordPress opens an HTTP connection to itself (the loopback request), which consumes a PHP-FPM worker for the duration of the cron run. On a server with 5 PHP workers, that's 20% of your capacity tied up processing cron while visitors wait for the remaining 4 workers. A cron job that takes 30 seconds to run (a large backup, a full WooCommerce order sync) holds that worker the entire time.
So the performance argument comes down to worker pool contention on busy sites. A site getting 50 visitors per hour won't notice. A WooCommerce store doing 500 orders per day on a shared hosting plan will.
Where WP-Cron falls apart
Speed is secondary. The real case for switching to server cron is reliability. WP-Cron has structural weaknesses that no amount of optimization can fix because they come from its design, not from bugs.
Traffic dependency
If your site gets fewer than a hundred visits per day, WP-Cron tasks will run late. How late depends on when visitors show up. A backup scheduled for 3 AM on a site with no overnight traffic won't execute until 8 or 9 AM. Scheduled posts miss their publish window. WooCommerce sales campaigns don't activate on time.
Server cron doesn't have this problem. A crontab entry running every 5 minutes fires 288 times per day whether anyone visits the site or not.
Caching interference
Full-page caching plugins (WP Super Cache, LiteSpeed Cache, W3 Total Cache) and CDNs like Cloudflare serve static HTML without executing PHP. If a visitor hits a cached page, WordPress never loads, and WP-Cron never checks. The entire trigger chain is broken, and nothing tells you about it.
Server cron bypasses this completely. A crontab entry calls WP-CLI or hits wp-cron.php directly, independent of any caching layer.
The stampede problem
On high-traffic sites, WP-Cron creates a different kind of trouble. Picture 20 requests hitting your server within the same second. Each one runs wp_cron(), each one sees overdue events, and each one tries to fire the background request. WordPress uses a transient lock (doing_cron) to prevent duplicate execution, but under heavy concurrency the lock check itself becomes a race condition: two requests both read "unlocked" before either writes "locked." Result: the same cron event runs twice.
For most tasks that's harmless duplication. For payment processing or email sending, it creates real problems. Server cron avoids this entirely because there's exactly one trigger, on a clock, not 20 triggers competing within a one-second window.
Three ways to trigger WordPress cron from the server
If you decide to switch, you have three options for the trigger itself. Each has trade-offs worth understanding before you commit.
curl or wget to wp-cron.php
*/5 * * * * curl -s https://yoursite.com/wp-cron.php > /dev/null 2>&1
This mimics what WP-Cron does internally: make an HTTP request to wp-cron.php. Simple to set up, works on any hosting with crontab access. But it has the same failure modes as the loopback: DNS resolution issues, firewall blocks, SSL certificate problems, and security plugins returning 403. You're also exposing wp-cron.php as a public URL, which some security audits flag.
WP-CLI (recommended for VPS and dedicated servers)
*/5 * * * * cd /var/www/yoursite && wp cron event run --due-now --quiet 2>&1 | logger -t wp-cron
WP-CLI runs WordPress directly via PHP on the command line. No HTTP request, no loopback, no SSL, no firewall, no DNS. Errors show up in the process output instead of disappearing into a failed HTTP response. If you have SSH access, this is the better choice.
One thing to watch: WP-CLI boots the entire WordPress stack (plugins, theme, database connection) for each run. On a site with 40 plugins, that boot takes 400 to 600 milliseconds. On a 5-minute schedule, that's 288 boots per day. Not a problem on most servers, but worth knowing if you're on a resource-constrained plan.
External cron service
No server access? An external cron service makes the HTTP request from outside your infrastructure. The trigger is independent of your server, which eliminates loopback issues entirely. This is the only option for shared hosting and managed WordPress hosts that don't expose crontab.
We compared services in our guide to replacing WP-Cron. The short version: free services (cron-job.org) give you the trigger but no failure alerts. Paid services add monitoring and response logging so you know when something breaks.
Making the switch
Two changes, regardless of which trigger method you pick.
First, add this to wp-config.php:
define('DISABLE_WP_CRON', true);
This stops the on-every-page-load check. Plugins can still schedule events through the WordPress cron API. The events just sit in the queue until your external trigger processes them.
Second, set up your trigger (crontab, WP-CLI, or external service). A 5-minute interval works for most sites. WooCommerce stores with time-sensitive order processing can go down to 1 minute. Going faster than every minute is rarely necessary and adds server load with no real benefit.
For the full step-by-step walkthrough, see the complete guide to replacing WP-Cron. If you need help with the cron expression syntax, the visual builder shows exactly when each schedule fires.
After the switch: knowing it still works
Here's the part that every "disable WP-Cron" tutorial skips. You set up the crontab, confirm it runs today, and move on. Three months later a server migration drops the crontab entry, or a WordPress update resets wp-config.php, or a security plugin starts blocking the endpoint. Cron silently stops. No error, no notification, no dashboard warning.
A crontab entry is invisible by design. It either works or it doesn't, and it won't tell you which. Even piping output to a log file doesn't help much if nobody reads the logs.
WatchCron's Cloud Cron for WordPress handles both the trigger and the monitoring. It hits wp-cron.php on your schedule and logs the HTTP status, response time, and response body for every execution. If the response code changes from 200 to 403, or response time spikes from 200ms to 30 seconds, you get an alert through Slack, Telegram, or email before the missed tasks pile up.
The free plan covers 3 cloud cron tasks. For most WordPress sites running cron every 5 minutes, that's enough. The Starter plan handles agencies managing multiple client sites with 75 monitored tasks.
When you should not switch
Not every WordPress site needs server cron. If your site gets consistent traffic throughout the day (200+ visits daily), doesn't run time-sensitive scheduled tasks, and doesn't use full-page caching that bypasses PHP, WP-Cron works fine. The 18-millisecond overhead is invisible, and the trigger fires often enough to keep the queue current.
Personal blogs, portfolio sites, small informational pages where a 15-minute delay on a scheduled post doesn't matter: keep WP-Cron enabled, skip the added complexity, and spend your time on something that actually moves the needle.
For everything else (WooCommerce stores, membership sites, sites behind aggressive caching, staging environments, anything where "the backup should run at 3 AM" needs to mean 3 AM), switch to server cron and set up monitoring so you know it stays running.