How to clean up and optimize a WordPress database, and what it does for speed
Cleaning a WordPress database makes it smaller and its backups quicker. Do not count on it for faster pages. The database work that can affect speed is trimming autoloaded options and adding a persistent object cache. Back up first, because a delete cannot be undone.
- By
- WP Ministry
- Updated
- Tested on
- WordPress 7.1.3, PHP 8.3.35
In short
- Export the database before you delete anything, and try the cleanup on a staging copy first.
- Autoloaded options are read on every page WordPress builds. Keep their total under 800 KB.
- Deleting revisions, trash and spam makes the database smaller. Do not expect faster pages from it.
- WordPress already clears auto-drafts after 7 days and the trash after 30.
- A table left by a removed plugin is safe to drop only once you know which plugin made it.
- Optimize tables after a large delete, not on a schedule for its own sake.
Cleaning a WordPress database means deleting what the site no longer needs: old revisions, items in the trash, spam comments, expired temporary values and tables left by plugins you removed. It makes the database smaller, and backups and moves quicker. Do not count on it to make pages faster for visitors.
Two things in the database can affect speed. One is the set of options WordPress loads on every page it builds, called autoloaded options. The other is whether the site has a persistent object cache. Start with a backup, do those two first if speed is the goal, and treat the rest as tidying.
What each step can and cannot do
| Step | What it changes | What to expect |
|---|---|---|
| Trim autoloaded options | Data read on every page WordPress builds | Can help every page that is not served from a page cache |
| Add a persistent object cache | How often WordPress has to ask the database | Can help the same pages. Your host has to offer it |
| Delete revisions, trash and spam | The size of the posts and comments tables | A smaller database and backup. Do not expect faster pages |
| Delete expired transients | Rows in the options table | A tidier table. WordPress clears these itself in time |
| Drop tables of removed plugins | Disk space | Space only |
| Optimize tables | How the tables are stored on disk | Space handed back after a large delete |
| Limit revisions | How fast the database grows | Nothing today. Less to clean later |
A page cache saves finished pages as static files and serves those, so a page that is already saved does not wait on the database. That is why most of this list changes little for visitors. How to speed up a slow WordPress site gives the full order of work, and the database comes last in it.
Back up first, and try it on a copy
With WP-CLI, this writes the whole database to one file:
wp db export ~/before-cleanup.sqlYou should see "Success: Exported to" and the file's full path. The ~/ puts the file in your home folder. A file in the site's public folder can be downloaded by anyone who guesses its name. To go back, import it:
wp db import ~/before-cleanup.sqlThe import puts every table back as it was at the export. Anything saved since then, such as an order, a comment or an edit, is lost.
Without WP-CLI, use your host's backup tool or phpMyAdmin: select the database, open the Export tab and download the file. A backup plugin does the same job; see WordPress backup plugins compared.
Run the cleanup on a staging copy of the site first. Check the pages, the forms and the dashboard there before you repeat it on the live site.
See how big the database is
In the dashboard, go to Tools, then Site Health, then the Info tab. The "Directories and Sizes" section shows the total size of the database.
WP-CLI shows where the size is, largest table first:
wp db size --tables --all-tables-with-prefix --human-readable --orderby=size --order=descWrite the figures down to compare later. WordPress itself has twelve tables on a single site: posts, postmeta, comments, commentmeta, options, terms, termmeta, term_, term_, links, users and usermeta, each behind your table prefix, which is usually wp_. Every other table was made by a plugin or a theme.
A large posts table can point to revisions. A large options table can point to transients or oversized options. A large table with a plugin's name on it is that plugin's own data, such as a log.
Trim autoloaded options
WordPress keeps settings as rows in the options table. Rows marked to autoload are fetched together, in one query, on every page request. Plugins and themes decide which of their own options are loaded this way.
WordPress's performance guide says too many autoloaded options can slow a site down and advises keeping the total under 800 KB. Since WordPress 6.6, Site Health reports a critical issue titled "Autoloaded options could affect performance" when the total is larger than that.
Step 1: Check Site Health
On WordPress 6.6 or later, go to Tools, then Site Health, and look on the Status tab for that issue. If it is not there, the total is under the limit and this section will gain you little.
Step 2: Measure the total
This counts the autoloaded rows and adds up their size in bytes. 800 KB is about 800,000 bytes. If your prefix is not
wp_, change the table name to match.bashwp db query "SELECT COUNT(*) AS options, SUM(LENGTH(option_value)) AS bytes FROM wp_options WHERE autoload IN ('yes','on','auto','auto-on');"Step 3: List the largest
The four values in the query are the ones WordPress treats as "load this on every page".
bashwp db query "SELECT option_name, LENGTH(option_value) AS bytes FROM wp_options WHERE autoload IN ('yes','on','auto','auto-on') ORDER BY bytes DESC LIMIT 20;"Step 4: Find out what each large one belongs to
Look for a plugin's name or initials at the start of each option's name. Sort the large ones into three groups: options of a plugin you have removed, options of an active plugin, and WordPress's own. Leave WordPress's own alone.
Step 5: Turn autoload off, one option at a time
Start with options of removed plugins. The first command prints the current value, so write it down. The second stops the option from loading on every page.
bashwp option get-autoload example_plugin_log wp option set-autoload example_plugin_log offStep 6: Look at the site, then measure again
Open the pages that matter, then run the total again. To undo a change, run
set-autoloadwith the value you wrote down.
Turning autoload off deletes nothing. The option stays in the table and is read when something asks for it.
Be more careful with an active plugin. WordPress's guidance is that an option used in several places on the front of the site should autoload, and one used only on a few addresses should not. If you cannot tell which kind an option is, ask the plugin's developer first.
Once a removed plugin's option has been off for a while with no ill effect, you can delete it with wp option delete example_. Only the backup brings it back.
Add a persistent object cache
Without one, WordPress reads its options from the database for every page it builds. A persistent object cache keeps that data in memory between requests, and WordPress's guide says options then load faster whether they autoload or not. With one in place, transients are also kept in the cache and not in the database.
It needs a cache server such as Redis or Memcached, which is your host's to offer. Site Health recommends one when it judges that the site would gain from it. WordPress caching plugins compared explains the kinds of cache and which plugins can use one.
Delete revisions, trash and spam
WordPress already clears some of this itself.
- Revisions. WordPress stores a record of each saved draft and each published update, as rows in the posts table, and by default it keeps every one. It has no screen for deleting them.
- Autosaves. There is at most one per user for each post, and a new one overwrites the old. They do not pile up.
- Auto-drafts. WordPress deletes those older than 7 days itself.
- Trash. Posts, pages, attachments and comments in the trash are deleted for good after 30 days by default.
- Spam comments. They are kept under Spam on the Comments screen, where you can clear them.
That leaves revisions, which grow without a ceiling, and spam, which is worth a look. Count before you delete:
wp post list --post_type=revision --format=count
wp post list --post_type=post,page --post_status=trash --format=count
wp comment list --status=spam --format=countThen run the matching line for each count above zero. Skip a line whose count was zero, because the command needs at least one ID.
wp post delete $(wp post list --post_type=revision --format=ids) --force
wp post delete $(wp post list --post_type=post,page --post_status=trash --format=ids) --force
wp comment delete $(wp comment list --status=spam --format=ids) --forceEach deleted item is reported on its own line, such as Success: Deleted post 1268.
Deleting revisions removes the history of everything that keeps one. Nobody can go back to an earlier version of a page afterwards. If that matters to you, skip the first line and limit revisions instead, as described below.
In the dashboard, the Comments screen has an Empty Spam button under Spam and an Empty Trash button under Trash. Each deletes everything in its view for good.
WordPress's performance guide files this step under reducing clutter. Where it names something in the database that slows a site, it names autoloaded options. Expect a smaller database, and no more.
Delete expired transients
A transient is a value a plugin or WordPress stores for a set time. Without an object cache, transients are rows in the options table. WordPress's documentation says it cleans out expired ones infrequently, so they can build up.
wp transient delete --expiredThe answer looks like Success: 12 expired transients deleted from the database. This is safe. An expired transient is one WordPress will not use again, and code that uses transients has to cope with one being missing.
Find tables left by removed plugins
A plugin is meant to remove its options and tables when it is uninstalled, which means deactivated and then deleted from the Plugins screen. Whether it does is up to the plugin. Deactivating alone is not meant to remove data, and a plugin that skips the cleanup leaves its tables behind.
To see them, list every table with your prefix and set aside the twelve WordPress tables named above:
wp db tables --all-tables-with-prefixWhat is left belongs to plugins and themes, active or gone. Active plugins can keep live data in tables of their own, such as orders, form entries or logs, so an unfamiliar table is not yet a leftover.
Step 1: Identify the owner
Look for a plugin's name or initials in the table name, and search that plugin's documentation for it. If you cannot tell what made a table, leave it.
Step 2: Confirm the plugin is gone for good
Check that it is not on the Plugins screen, active or inactive, and that you will not install it again. Dropping the table deletes that plugin's data.
Step 3: Export that table on its own
Here
wp_stands for the table's real name. Theexample_ log ~/keeps the file in your home folder, outside the site's public folder.bashwp db export --tables=wp_example_log ~/example-log.sqlStep 4: Drop it
DROP TABLEremoves the table and every row in it.bashwp db query "DROP TABLE wp_example_log;"Step 5: Check the site
Open the site and the dashboard. If something breaks, put the table back with
wp db import ~/.example-log.sql
Dropping an unused table frees disk space and nothing else.
Optimize the tables
After a large delete, the space the rows took is still held inside the table. Optimizing hands it back.
wp db optimizeIt runs the database's optimize command on every table and ends with Success: Database optimized.
What that command does depends on how a table is stored. The MySQL manual says that for InnoDB tables it rebuilds the table, which updates the index statistics and frees unused space. During the run you may see "Table does not support optimize, doing recreate + analyze instead" for each table. That is the normal message for InnoDB, not an error.
Keep expectations modest:
- The MySQL and MariaDB manuals both tie this command to a large delete or many changes. Run it after a cleanup that removed a lot.
- The MySQL manual says some fragmentation is expected, and that disk space can go back to the operating system when a table is stored in a file of its own.
- Rebuilding a large table takes time. MySQL locks an InnoDB table only briefly at the start and the end, but pick a quiet hour anyway.
Optimizing is not repairing. If WordPress reports that a table is damaged, the repair steps are in how to fix the error establishing a database connection.
Keep it from growing back
To cap revisions, add this line to wp-config.php, above the line that says "That's all, stop editing".
define( 'WP_POST_REVISIONS', 10 );WordPress then keeps that many revisions for each post, plus one autosave per user. Older ones are deleted the next time that post is updated. Setting the constant to false stores no revisions at all, which takes away the way back from a bad edit. Remove the line to return to keeping every revision.
The trash can be emptied sooner than 30 days:
define( 'EMPTY_TRASH_DAYS', 7 );Do not set it to zero. That switches the trash off, and WordPress then deletes for good without asking.
What a cleanup plugin does instead
A cleanup plugin runs the same deletes from a screen in the dashboard and can repeat them on a schedule. It suits a site with no command-line access. Two examples, each from its own listing:
- WP-Optimize, by Team Updraft, cleans post revisions, auto-drafts, trashed posts, spam and trashed comments. It can run on a schedule, from daily to monthly, and can keep a set number of weeks of data. It has a free version and paid features. Its listing says that when it detects InnoDB tables, optimizing tables on disk is not available and the other cleanup features still work.
- Advanced Database Cleaner, by Younes JFR., deletes old revisions, auto-drafts, spam and trashed comments, expired transients and unused metadata, with a preview first and a rule to keep the last days you choose. Finding which plugin owns a table or an option, and which ones are orphaned, is in its paid version.
Both listings say to back up the database first. Use one tool for this job. A scheduled cleanup deletes without anyone looking, so set it to keep recent data.
What not to rely on
- Deleting revisions to make pages faster. It makes the database smaller. Measure a page before and after to see what it did for yours.
- Optimizing every week. The manuals describe it as something to do after large changes.
- Dropping tables you do not recognize. They may hold live data.
- Cleaning in place of the real fix. If pages are slow, check the hosting, the page cache, the images and the plugins first.
Our speed optimization service is a one-time job on a WordPress site that has become slow: you name the pages that matter most, and we measure them before the work and again after it.
Common questions
Will cleaning the database make my site faster?
It depends on what you clean. Bringing a large set of autoloaded options back under 800 KB can help every page WordPress builds. Deleting revisions, trash and spam shrinks the database and its backups, and a page served from a page cache never touched them.
Is it safe to delete all post revisions?
The published content stays as it is. Every earlier version goes, so nobody can restore one afterwards. Export the database first. To keep some history, set WP_ to a number and let WordPress trim each post as it is next updated.
Why is the database the same size after I deleted so much?
Deleted rows leave gaps inside the table, and the table keeps the space. Run wp db optimize to rebuild the tables, then check the size again. The MySQL manual says the space can return to the operating system for tables stored in a file of their own.
How often should I clean the database?
No schedule suits every site. WordPress clears auto-drafts, old trash and expired transients on its own, and a revision limit handles revisions. Check the size and Site Health when you do your other upkeep, and clean when one of them shows a reason.

