WORDPRESS
July 30, 2026

How to Fix Slow WordPress Admin Dashboard

6 min read
Author
CloudStick Team
WordPress Engineer
Share this article
How to Fix Slow WordPress Admin Dashboard
CloudStick
Slow
Admin

What's Actually Slowing Down wp-admin

Every wp-admin page runs through a completely different code path than your public site, which is exactly why a fast frontend can sit next to a wp-admin that takes eight seconds to open the Posts screen. Four things account for nearly all of it: the WordPress Heartbeat API polling admin-ajax.php every 15 to 60 seconds to check for autosave conflicts and post locks; a wp_options table bloated with autoloaded rows that WordPress reads into memory on literally every request, admin or not; active plugins that hook into admin_init or admin_enqueue_scripts and run their own queries, remote license checks, or update lookups on every single admin page regardless of whether that page needs them; and the absence of persistent object caching, which means every one of those queries hits MySQL cold instead of being served from memory.

None of these are frontend problems. Your page cache, your CDN, and your Nginx FastCGI cache do nothing for wp-admin, because that traffic is never meant to be cached in the first place — it's logged-in, dynamic, and unique per admin action. The fixes below go through the four causes in the order that gives you the fastest signal: throttle Heartbeat first because it's a two-minute change, check autoloaded options size because it tells you whether you have a structural database problem, isolate the offending plugin because it's usually one specific plugin doing something expensive on every load, and add object caching last because it has the biggest overall effect but takes the most setup.

Throttle the Heartbeat API

Open your browser's network tab on any wp-admin screen and you will see a request to admin-ajax.php firing every 15 seconds on the post editor and every 60 seconds on the dashboard — that's the Heartbeat API, and each one of those requests boots the full WordPress core, runs every plugin hooked into heartbeat_received, and often touches the database. With several editors working simultaneously, or several browser tabs left open, this adds up to a steady background load that has nothing to do with anything a person is actively doing.

You rarely need 15-second polling outside of active co-editing. Raise the interval and drop it entirely on screens that don't need it, such as the main dashboard widgets:

add_filter( 'heartbeat_settings', function( $settings ) {
$settings['interval'] = 60; // seconds, default is 15
return $settings;
} );
add_action( 'admin_enqueue_scripts', function() {
$screen = get_current_screen();
if ( $screen && $screen->id === 'dashboard' ) {
wp_deregister_script( 'heartbeat' );
}
} );

Add this to your active theme's functions.php or a site-specific plugin. Leave Heartbeat running normally on the post editor itself — that's where it does real work preventing two editors from overwriting each other's changes — but there is no reason the dashboard or the plugins screen needs a 15-second poll to sit there ticking in the background.

Audit Autoloaded Options in wp_options

Every row in wp_options with autoload set to yes gets pulled into memory on every single page load — admin and frontend alike — through wp_load_alloptions(). A healthy site keeps that total well under a megabyte or two. A site with a runaway transient problem can easily push it into tens of megabytes, and since that entire blob has to be unserialized before WordPress can do anything else, wp-admin pays that cost on every screen change.

Check the total size and find the worst offenders directly:

SELECT SUM(LENGTH(option_value)) AS total_autoload_bytes
FROM wp_options
WHERE autoload = 'yes';
SELECT option_name, LENGTH(option_value) AS size_bytes
FROM wp_options
WHERE autoload = 'yes'
ORDER BY size_bytes DESC
LIMIT 20;

Look specifically for rows named _transient_ or _site_transient_ that are large and set to autoload yes — WordPress's own transient API is supposed to mark these to expire, but plugins that write transients directly with wp_options queries, or that never clean up after themselves, leave stale rows behind indefinitely. If you have WP-CLI available, wp transient delete --expired clears out anything past its expiration safely. For rows that aren't expiring transients but are just large and unnecessary at every load — cached API responses, serialized settings blobs a plugin never needed to autoload — the fix is to update that specific option's autoload flag to no, which stops it from being pulled in on every request while still leaving it available when the plugin explicitly asks for it.

Isolate the Culprit Plugin

Deactivate every plugin, load wp-admin, and time it — then reactivate plugins one at a time, timing the load after each one, until you see a sudden jump. That jump identifies the plugin doing something expensive on admin_init or admin_enqueue_scripts, and it is almost always just one or two plugins, not the total count. A site running forty lightweight, well-behaved plugins can load wp-admin faster than a site running five plugins where one of them checks a remote license server or scans the filesystem on every admin page load.

It isn't the number of plugins that determines wp-admin speed — it's whether any single one of them runs a database query, a remote API call, or a filesystem scan on every admin_init hook, on every admin page, regardless of whether that specific page needs it.

If manually toggling plugins is too slow, install Query Monitor temporarily — it breaks down exactly which hook fired which queries and how long each one took, per plugin, on the actual page you're looking at. That turns a guessing game into a direct read of which plugin is responsible, and you can usually find the answer in under five minutes instead of an hour of manual isolation.

Enable Object Caching and Next Steps

Without persistent object caching, every one of those admin AJAX calls, every Heartbeat tick, and every plugin query hits MySQL cold, on every single request, because WordPress's default object cache only lives for the duration of one page load and is thrown away immediately after. A persistent cache backed by Redis keeps that data in memory between requests, so the same query that runs on page one doesn't need to run again on page two — it's the single change that compounds with everything else on this list. CloudStick's built-in Redis object caching integration for WordPress handles exactly this, speeding up admin AJAX calls the same way it speeds up the public frontend, without needing to hand-install and configure a drop-in object cache file yourself.

Work through these in order: throttle Heartbeat so background polling stops adding load that has nothing to do with what an admin is actually doing, run the autoload query to confirm whether wp_options itself is the bottleneck and clean up anything oversized, isolate the specific plugin responsible rather than assuming it's just "too many plugins," and turn on persistent object caching so the queries that remain don't hit the database raw every time. Most slow wp-admin cases resolve after the first two steps alone — the plugin isolation and object caching layers are there for the cases that don't.

Leave a comment
Full Name
Email Address
Message
Contents