Your WordPress site feels slow, so you swap the theme, install a caching plugin, maybe pay for a bigger server. It’s a little faster. Then a month later it’s crawling again. If that cycle sounds familiar, the problem probably isn’t your theme or your host — it’s the database quietly bloating underneath everything.
WordPress runs on MySQL, and every plugin, setting, draft, and page view leaves a trace in it. Most of that data is useful. A surprising amount is dead weight that never gets cleaned up: expired caches that were never purged, thousands of old post revisions, and settings from plugins you deleted years ago that are still being loaded on every single request.
The last site we cleaned up had a wp_options table over a gigabyte — and roughly 90% of it was expired transients and event logs from an analytics plugin the owner had removed eight months earlier. The plugin was gone. Its garbage wasn’t. Here’s how to find that kind of rot on your own site and clear it out safely.
Where WordPress Database Bloat Actually Comes From
Database bloat isn’t one problem, it’s several small ones that compound. Before you start deleting anything, it helps to know what the usual suspects are and why each one hurts performance in a different way.
Autoloaded options: the tax you pay on every page load
This is the big one, and almost nobody looks at it. WordPress stores site-wide settings in the wp_options table, and each row has an autoload flag. Every option marked to autoload gets pulled into memory on every request — front-end pages, admin screens, AJAX calls, REST requests, all of them — through a single query that WordPress caches as alloptions. That’s efficient when the data is small. It becomes a real drag when a badly-behaved plugin dumps a few megabytes of logs, cron history, or serialized junk into an autoloaded row.
WordPress 6.6, released in July 2024, added automatic protection here: options larger than a threshold (150KB by default, filterable) are no longer set to autoload when they’re created or updated. That helps going forward, but it doesn’t retroactively fix the oversized options already sitting in your database from older plugins. You still have to find and fix those yourself.
Post revisions pile up forever
Every time you save a post or page, WordPress keeps the previous version as a revision. It’s a genuinely useful safety net, but out of the box the number of revisions per post is unlimited. A page that’s been edited two hundred times carries two hundred full copies of its content in the wp_posts table, plus all their metadata. On a content-heavy site that’s edited often, revisions alone can account for more rows than your actual published content.
Transients, orphaned meta, and dead-plugin leftovers
Transients are WordPress’s built-in way to cache temporary data — an API response, a computed menu, a “you have updates” notice — with an expiration time. When your site has no persistent object cache (no Redis or Memcached), transients get written straight into wp_options. The catch is that expired transients aren’t reliably deleted the moment they lapse; they linger until something specifically cleans them up. Add orphaned post metadata, comment meta with no parent comment, and settings tables left behind by uninstalled plugins, and you’ve got a database carrying a lot of data that no living code will ever read again.
A bloated wp_options autoload adds time to every request your site serves, before caching can even help. Slower server response feeds directly into a worse Time to First Byte, which Google folds into Core Web Vitals — the same signals that shape both your search ranking and how fast the page actually feels to a visitor. A lean database is one of the cheapest speed wins there is: no new plugin, no bigger server, just less dead weight.
Measure the Damage Before You Touch Anything
Never clean blind. You want to know what’s actually big before you start deleting, both so you fix the real problem and so you have a baseline to compare against afterward. Every command below uses WP-CLI, the official command-line tool for WordPress — run them over SSH from your site’s root directory.
Check your total autoload size
Start with the single most important number — how much data WordPress loads on every request:
wp db query "SELECT ROUND(SUM(LENGTH(option_value))/1024/1024, 2) AS autoload_mb \
FROM wp_options WHERE autoload IN ('yes','on');"
For reference, WordPress’s own Site Health tool (since version 6.6) flags autoloaded options as a problem once they cross 800KB, so treat that as your ceiling and aim well below it. If you’re seeing 3, 5, or 20 MB, something is dumping data where it doesn’t belong, and that’s your first target.
Find the biggest offenders by name
Now list the largest autoloaded options individually so you can see which plugin is responsible:
wp db query "SELECT option_name, ROUND(LENGTH(option_value)/1024, 1) AS size_kb \
FROM wp_options WHERE autoload IN ('yes','on') \
ORDER BY LENGTH(option_value) DESC LIMIT 20;"
The names usually give the culprit away — a prefix like edd_, wc_, or some abandoned plugin’s slug attached to a 4MB row. Note the WP 6.6 detail here: older databases store the flag as yes/no, while 6.6 and later write on/off. Checking for both, as these queries do, keeps you honest across any version.
Count your revisions and transients
Two quick counts tell you whether these are a problem on your site:
wp post list --post_type=revision --format=count
wp transient list --format=count
A few hundred revisions is normal. Tens of thousands means it’s worth trimming. And if the transient count is enormous, a good chunk of those are probably expired and safe to clear.
Every command in the next section modifies your database. Take a full backup before you run any of them — a fresh database export at minimum. wp db export backup.sql gives you a one-command dump you can restore with wp db import backup.sql if anything goes sideways. Test the cleanup on a staging copy first if you possibly can.
The Cleanup, Step by Step
With a backup in hand and your measurements taken, you can start clearing the dead weight. Work in this order — the safe, high-impact stuff first.
Clear expired transients
This is the safest cleanup you can do, because expired transients are by definition data WordPress has already decided it no longer needs:
wp transient delete --expired
If you want to be more aggressive and you’re confident nothing critical depends on a currently-cached transient, wp transient delete --all clears the lot; WordPress simply regenerates what it needs on the next request.
Trim old post revisions
Delete the accumulated revisions with a single piped command:
wp post delete $(wp post list --post_type=revision --format=ids) --force
The --force flag skips the trash and removes them outright, which is what you want for revisions. To stop them piling up again, add a cap to wp-config.php so WordPress only keeps the last few versions of each post:
define( 'WP_POST_REVISIONS', 5 );
Fix oversized autoloaded options
Once you’ve identified a bloated autoloaded option that a plugin left behind, you have two moves. If the option is genuinely obsolete — from a plugin you no longer run — delete it: wp option delete the_option_name. If the data is still used but has no business loading on every request, flip its autoload flag off instead of deleting it: wp option set the_option_name "$(wp option get the_option_name)" --autoload=no. Be deliberate here; deleting an option that a live plugin depends on can break its settings, so confirm what owns it first.
Optimize the tables
After deleting a lot of rows, MySQL leaves behind gaps where that data used to be. Reclaim the space and rebuild the indexes:
wp db optimize
That runs OPTIMIZE TABLE across your database. Re-run your autoload measurement from earlier and compare — on a badly bloated site, watching that number drop from double-digit megabytes back under one is genuinely satisfying.
wp db export backup.sql
wp transient delete –expired
wp post delete $(wp post list –post_type=revision –format=ids) –force
wp option delete <dead_option_name>
wp db optimize
Keeping It Lean Without Thinking About It
A one-time cleanup feels great, but the bloat comes back if nothing changes. The point isn’t to scrub the database every weekend — it’s to set up a few habits so it never gets bad again.
Cap revisions in wp-config.php as shown above, and set an autosave interval that suits how you work. Uninstall plugins properly rather than just deactivating them, and prefer plugins that actually clean up their own options and custom tables on uninstall — a well-built plugin removes its footprint when you tell it to leave. If you run a lot of plugins, a persistent object cache like Redis moves transients out of wp_options entirely, which sidesteps a whole category of this problem. And schedule a lightweight recurring task — a monthly WP-Cron event or a server cron running wp transient delete --expired and wp db optimize — so routine buildup gets swept without you lifting a finger.
None of this is glamorous, and none of it shows up in a page builder. But a database that stays small is a site that stays fast, and it costs you nothing but a little discipline up front.
Frequently Asked Questions
A fast site starts with a database that isn’t carrying years of dead weight. Run the measurements above on your own site — you might be surprised what’s been loading on every page this whole time.
Built by amplifi.studio — see also The Slow-Site Tax: How to Fix WordPress Core Web Vitals.