WordPress Heartbeat API Eating CPU? Here's How to Fix It

· 5 min read · Getwebup

If your hosting dashboard shows a WordPress site pegging the CPU even when nobody's actively editing anything, open your server's access log and look for repeated POST requests to /wp-admin/admin-ajax.php. If they're firing every 15 to 60 seconds from open browser tabs, you've found your culprit: the WordPress Heartbeat API.

Symptom: Steady CPU Load With No Obvious Traffic Spike

This one's easy to misdiagnose because it doesn't look like a traffic problem. Your visitor numbers are normal, there's no DDoS, no crawler storm - but your VPS load average sits stubbornly high, or on shared hosting you keep hitting a CloudLinux LVE resource limit. Check your access log:

tail -f /home/username/access-logs/yourdomain.com | grep admin-ajax.php

If you see a wall of POST requests to admin-ajax.php, cross-reference the timing. Heartbeat fires roughly every 15 seconds on post-edit screens and every 60 seconds on the wp-admin dashboard by default. A handful of staff who leave their WordPress admin tab open all day is enough to keep a small VPS busy around the clock.

Cause: What the Heartbeat API Actually Does

Heartbeat isn't a bug - it's a real feature WordPress core introduced to support things like:

  • Auto-save and post-lock warnings ("this post is being edited by another user")
  • Live session expiry checks and login-timeout warnings
  • Plugin dashboards that need near-real-time updates (some page builders, some security plugins)

The problem is that every one of those AJAX calls is a full WordPress bootstrap: PHP loads, plugins init, and in a lot of cases a database query runs. Multiply that by every open admin tab, every 15-60 seconds, across every logged-in editor, and you get a steady background load that never shows up as a "traffic spike" but absolutely shows up in your hosting bill or resource warnings.

It gets worse on WooCommerce and membership sites, where some front-end pages also load Heartbeat for cart or session syncing - so it's not always confined to /wp-admin/.

Fix: Throttle It, Don't Just Kill It

Completely disabling Heartbeat is tempting, but it breaks post-locking (two editors can silently overwrite each other's work) and session-expiry warnings. The safer move is to slow it down and limit where it runs.

1. Confirm the diagnosis first

Before changing anything, install Query Monitor or check your browser's Network tab on wp-admin with a filter for admin-ajax.php. Confirm the action=heartbeat parameter is actually what's firing repeatedly - some plugins fake similar polling patterns and you don't want to "fix" the wrong thing.

2. Throttle the interval with a plugin

The simplest fix for most site owners is the free Heartbeat Control plugin. It lets you set separate behavior for the dashboard, post editor, and front end without editing code:

  • Dashboard: slow to 60-120 seconds (or disable entirely if nobody needs live updates there)
  • Post editor: keep it enabled but slow to 30-60 seconds so autosave/post-lock still work
  • Front end: disable unless you're running WooCommerce cart features that depend on it

3. Or throttle it in code (no plugin)

If you'd rather not add another plugin, drop this in your theme's functions.php or a site-specific plugin:

add_filter( 'heartbeat_settings', function ( $settings ) {
    $settings['interval'] = 60; // seconds, minimum enforced is 15
    return $settings;
} );

add_action( 'init', function () {
    if ( ! is_admin() ) {
        wp_deregister_script( 'heartbeat' );
    }
}, 1 );

That keeps Heartbeat alive in wp-admin (so post-locking still works) but strips it from front-end pages entirely - usually the biggest win on WooCommerce or membership sites.

4. Check for plugin-specific Heartbeat abuse

Some page builders and security plugins hardcode their own aggressive polling on top of core Heartbeat. If CPU stays high after throttling core Heartbeat, deactivate plugins one at a time and re-check admin-ajax.php traffic - Elementor, Divi, and a few live-stats security plugins are repeat offenders here.

5. Verify with server-side monitoring

On a VPS, watch load before and after with:

top -o %CPU

On cPanel/shared hosting, check WHM's Resource Usage or your CloudLinux LVE stats page for the account. You should see PHP process counts drop noticeably within a few minutes of the fix taking effect - Heartbeat calls tend to be short but frequent, so the change shows up fast.

Prevention: Keep Heartbeat From Creeping Back Up

  • Audit new plugins before activating them - check if they add their own AJAX polling, not just Heartbeat hooks.
  • Set a site policy for idle admin tabs - if your team routinely leaves 5-10 wp-admin tabs open overnight, that's constant background load for no reason. A simple "close the tab when you're done" habit saves real CPU.
  • Re-check after major WordPress or plugin updates - Heartbeat behavior and defaults have shifted across WP versions, and plugin updates can silently re-enable front-end polling you'd previously turned off.
  • Pair this with object caching - if you're on a Getwebup VPS, adding Redis object cache reduces the DB load each Heartbeat tick causes, even if you can't fully control how often it fires.

None of this is a one-time fix-and-forget. Heartbeat settings live in code or plugin config, and both can get reset by updates - so it's worth a quick recheck of admin-ajax.php traffic whenever CPU usage creeps up again for no clear reason.

Questions people actually ask