Every WordPress site runs on a MySQL or MariaDB database, and every one of those databases gets messier with age. Revisions pile up, plugins leave tables and options behind after you remove them, WooCommerce logs scheduled actions by the thousand, and a few oversized “autoloaded” options quietly add time to every single page view.
This guide is the checklist we use when a site’s admin feels sluggish or its time to first byte (TTFB) creeps up. It is ordered from safest to riskiest. Each step tells you how to measure the problem first, so you only clean what is actually costing you speed.
Before you touch anything: back up and measure
Take a full database backup you have tested restoring, ideally on a staging copy of the site. Then record a baseline so you can prove the cleanup helped:
- Database size per table. In phpMyAdmin, or with WP-CLI:
wp db size --tables --human-readable. Note the largest tables. - Autoloaded data size.
wp option list --autoload=on --format=total_bytes. Since WordPress 6.6, Site Health also warns when autoloaded options pass about 800 KB. - TTFB on a few uncached pages.
curl -o /dev/null -s -w '%{time_starttransfer}\n' https://example.com/?nocache=1, run several times and averaged. - Slow queries. Query Monitor’s “Queries by Component” panel shows which plugin runs which queries and how long they take. See finding N+1 queries with Query Monitor.
Step 1: Autoloaded options (the bloat that costs you on every request)
Most database clutter just takes up disk space. Autoloaded options are different: WordPress loads every option marked for autoload into memory on every request, before any template runs. A few megabytes of autoloaded data is a tax on every page view, in the admin and on the front end.
Find the biggest offenders:
SELECT option_name, ROUND(LENGTH(option_value)/1024) AS kb
FROM wp_options
WHERE autoload IN ('yes','on','auto-on','auto')
ORDER BY LENGTH(option_value) DESC
LIMIT 20;
(Replace wp_ with your table prefix. WordPress 6.6 introduced the newer on/auto values alongside the legacy yes.)
What usually turns up:
- Leftovers from removed plugins. Option names that clearly belong to a plugin you no longer run. Once you have confirmed with a search of the codebase, these can be deleted.
- Large caches stored as options. Rendered CSS, remote API responses, license data or stats. These rarely need to load on every request. Set them to not autoload (
wp option set-autoload <name> offon recent WP-CLI) rather than deleting them. - Transients that never expire. See step 2.
Since 6.6, WordPress no longer autoloads newly added or updated options above roughly 150 KB unless a plugin explicitly asks it to. So bloat that is still there is either old, or a plugin forcing it.
Step 2: Transients
Transients are cache entries with an expiry time. They are safe to delete by definition, because WordPress or the plugin rebuilds them when needed.
- Delete expired ones:
wp transient delete --expired - If the table is badly bloated, clear all of them:
wp transient delete --all
Then watch what comes back. If thousands of transients reappear within a day, a plugin has a broken expiry policy or a failing cron job. Fix that plugin rather than deleting the symptom every month. If you run a persistent object cache (Redis or Memcached), transients live there instead of in wp_options, which removes this whole category of bloat.
Step 3: Revisions, trash, spam and auto-drafts
WordPress keeps every revision of every post forever by default. A page edited 40 times carries 40 full copies in wp_posts.
- Cap future revisions in
wp-config.php:define( 'WP_POST_REVISIONS', 5 ); - Remove existing revisions in bulk (on staging first):
wp post delete $(wp post list --post_type=revision --format=ids) --force. Or use WP-Optimize or Advanced Database Cleaner, which show a preview before deleting. - Empty the trash and spam folders. Trashed posts and spam comments sit in the same tables as live content.
Step 4: Orphaned metadata
When posts, comments or terms are deleted outside the normal WordPress functions (bulk SQL, broken importers, some page builders), their metadata stays behind. These rows make every meta query slower. Count them first:
SELECT COUNT(*) FROM wp_postmeta pm
LEFT JOIN wp_posts p ON p.ID = pm.post_id
WHERE p.ID IS NULL;
If the number is significant, delete them with the same JOIN (DELETE pm FROM ... WHERE p.ID IS NULL) or with a cleanup plugin. Repeat the check for wp_commentmeta against wp_comments, and for wp_term_relationships against wp_posts.
Step 5: WooCommerce-specific bloat
Stores accumulate data that a brochure site never sees:
- Action Scheduler logs.
wp_actionscheduler_actionsandwp_actionscheduler_logscan grow to millions of rows on busy stores. Completed actions are kept for 30 days by default, adjustable with theaction_scheduler_retention_periodfilter. Check the pending and failed actions under WooCommerce › Status › Scheduled Actions too: thousands of failed actions point to a broken integration. - Customer sessions.
wp_woocommerce_sessionsis cleaned by a cron job. If WP-Cron does not run reliably, it grows without limit. - Order data. With HPOS enabled, orders live in their own tables (
wp_wc_ordersand related), which takes a large load offwp_postmeta. If you have migrated, make sure sync mode is not left running permanently. See HPOS in 2026.
Step 6: Tables left behind by removed plugins
Deleting a plugin rarely drops its custom tables. List tables that don’t belong to core or to active plugins: wp db tables --all-tables, then compare the prefixes (for example wp_wfls_, wp_yoast_, wp_redirection_) with your active plugin list. Export a table before you drop it. Some plugins share tables, and a table that looks orphaned may still be read by an add-on.
Step 7: Engine, indexes and the queries themselves
- InnoDB, not MyISAM. Old sites sometimes still have MyISAM tables, which lock the whole table on every write. Check with
SHOW TABLE STATUSand convert during a quiet hour. - Core indexes are already there. WordPress indexes post type, status, date and meta keys. The slow cases are usually queries that filter or sort by
meta_value, which is not indexed. That is why WooCommerce uses lookup tables such aswc_product_meta_lookup. If a custom query sorts thousands of posts by a meta value, the fix is usually a better query or a lookup table, not a new index. - Reclaim space. After large deletions,
OPTIMIZE TABLEon the affected tables returns the space to the server. On InnoDB this rebuilds the table, so run it outside busy hours.
What not to delete
| Data | Safe to remove? | Why |
|---|---|---|
| Expired transients | Yes | Cache by definition; rebuilt on demand |
| Old revisions, trash, spam | Yes, after a backup | No live content depends on them |
| Orphaned meta | Yes, after counting | References rows that no longer exist |
| Large autoloaded options | Usually de-autoload, don’t delete | An active plugin may still read them |
| Custom plugin tables | Only for plugins you removed | Active plugins and add-ons break silently |
| WooCommerce orders, customers, sessions in use | No | Business and tax records |
How often to do this
For most business sites: a scheduled monthly cleanup of transients, revisions and spam (WP-Optimize or a WP-CLI cron), and an autoload and table review every quarter or after removing a major plugin. Re-run your baseline measurements afterwards. If TTFB didn’t move, the bottleneck is elsewhere, usually PHP workers, missing page or object caching, or a slow plugin. See caching plugins compared.
Slow admin or high TTFB? We audit and clean WordPress and WooCommerce databases without breaking plugins, then measure the speed difference. See our maintenance and performance services.
Frequently Asked Questions
Will cleaning the database make my site faster?
Only if the database is the bottleneck. Autoloaded options and orphaned meta often are; old revisions usually only cost disk space. Measure TTFB and query times before and after so you know.
Is it safe to use a database cleanup plugin?
Yes, for the standard categories (revisions, transients, spam, trash), as long as you have a tested backup. Be careful with “clean orphaned tables or options” features: they guess, and a wrong guess can wipe a plugin’s settings.
Does WordPress 6.6 fix autoload bloat automatically?
Partly. It stops autoloading new large options by default and adds a Site Health warning, but it doesn’t clean up options that were already autoloaded before you updated.
