The Heartbeat API arrived in WordPress 3.6 (2013) to enable real-time browser-server communication: autosave, post-edit lock to prevent collisions, dashboard notification updates. It POSTs to admin-ajax.php every 15 seconds in the post editor and every 60 seconds elsewhere in wp-admin. It does not run on the front end. The catch: every open wp-admin tab keeps firing those requests even when the user is idle.
Why this matters
The math is simple. Four open wp-admin tabs from one editor = four requests every 60 seconds = 240 hourly requests against the server. Each one bootstraps WordPress fully - $alloptions hydration, hook firing, MySQL connection. On a small VPS (1 vCPU, 1GB RAM) that can be 30-50% of total CPU. With five concurrent editors, the server starts choking.
An innocent heartbeat usually costs 200-500ms of PHP work. On a slow site (heavy autoload, sluggish DB) it can hit 2-3 seconds. Each one occupies a PHP-FPM worker. With pm.max_children = 10 and eight workers locked on heartbeats, only two are left for real visitors.
How to detect
Open any wp-admin page. F12 > Network > filter XHR. Within 60 seconds you should see a POST to admin-ajax.php?action=heartbeat. In the post editor the cadence is 15 seconds.
For a deeper view, install Query Monitor. It logs each heartbeat's duration, query count, and active hooks. If a single heartbeat exceeds 300ms there is meaningful headroom to recover.
How to fix
Standard answer: WordPress.org's free "Heartbeat Control" plugin by LittleBizzy:
- Install and activate
- Settings > Heartbeat Control
- Frontend: "Disable Heartbeat" - it has no reason to run on the public site
- WordPress Dashboard: "Disable Heartbeat", or "Modify" with a 120-second interval if you depend on live notifications
- WordPress Post Editor: "Allow Heartbeat" at 60 seconds (no slower, or autosave breaks)
Manual alternative in your child theme's functions.php:
// disable heartbeat on the front end
add_action('init', function () {
if (!is_admin()) {
wp_deregister_script('heartbeat');
}
});
// throttle dashboard heartbeat to 120 seconds
add_filter('heartbeat_settings', function ($settings) {
$settings['interval'] = 120;
return $settings;
});To kill heartbeat fully on admin (not recommended with Gutenberg autosave):
add_action('admin_enqueue_scripts', function () {
wp_deregister_script('heartbeat');
});Common mistakes
Worst case: disabling heartbeat in the post editor too. Autosave stops, and concurrent edits by two authors collide silently (last save wins). Keep 60 seconds in the editor even when squeezing CPU. Second mistake: disabling the front end while leaving the dashboard at default - the dashboard is the big offender. Third: setting interval beyond 300 seconds - WordPress does not always honor values outside 15-120 and may behave unpredictably.
Verifying the fix
Open an admin dashboard, F12 > Network > XHR, wait a minute. No heartbeat request should appear (if disabled), or one should appear every 120 seconds (if throttled). In the editor, wait 60 seconds and confirm a single heartbeat. Type some text, wait a minute, then close the tab - WordPress should offer to restore on return. If it does not, autosave broke and your interval is too long.
To measure CPU savings, compare cPanel's "Resource Usage" before and after. A 10-30% drop during evening hours (when admin tabs are open) is realistic.