The quiet cost of old WordPress revisions
I once opened a WordPress database on my test VM and found that the content itself was not unusually large. The revision rows were. Nothing was broken, but every backup was carrying years of editing history that nobody had checked for a long time.
WordPress keeps a previous version when you save a post, page, or other revision-enabled content. That lets you recover deleted text, an older title, or a product description with a few clicks. It is a useful safety net.
On a site edited for years, that safety net can become a sizeable part of the database. Multi-author blogs, WooCommerce catalogs, and repeated saves in the block editor can create dozens or hundreds of revisions for one piece of content. Each revision is stored as a separate row in wp_posts. Some plugins may also create related data in wp_postmeta.
Let me put it this way: revision cleanup is maintenance, not a magic speed button. It can reduce backup sizes and improve some administrative queries, but it will not repair a slow plugin, a bad database query, or an undersized PHP-FPM pool.
Measure before deleting anything
I do not start database maintenance with a delete command. First I take a backup, confirm where WordPress is installed, and measure the current state. For a handful of posts, the Revisions panel in the dashboard is enough. For a large site, WP-CLI gives me a more useful view.
Count revisions with WP-CLI
Connect over SSH and change to the WordPress directory. If a command may run for more than a few seconds, I use tmux instead of trusting a bare SSH session. A dropped connection should not decide whether maintenance succeeds.
cd /var/www/html
tmux new -s wp-maintenance
wp db export before-revision-cleanup.sql
wp db query "SELECT COUNT(*) AS revision_count FROM wp_posts WHERE post_type = 'revision';"The export creates a database backup, and the final query counts revision rows. Your prefix may not be wp_; check $table_prefix in wp-config.php before using a direct SQL query.
That count is only a starting point. A few hundred rows may not matter on one site, while a large revision backlog can make backups and database work needlessly heavy on a small hosting plan.
wp db query "SELECT post_parent, COUNT(*) AS revision_count
FROM wp_posts
WHERE post_type = 'revision'
GROUP BY post_parent
ORDER BY revision_count DESC
LIMIT 20;"This shows which parent posts, pages, or products have accumulated the most revisions. If one item stands out, I inspect its editing workflow and the plugins that touch it before scheduling a bulk cleanup.
Inspect sample rows
I also check actual records rather than trusting a single total. The same query works in the MySQL client or phpMyAdmin:
SELECT ID, post_parent, post_date, post_title
FROM wp_posts
WHERE post_type = 'revision'
ORDER BY post_date DESC
LIMIT 20;Most titles will be generic revision titles. A revision normally points to its parent through post_parent. Rows with no sensible parent, or revisions belonging to content that was already deleted, deserve a closer look. I do not delete those rows from wp_postmeta by guesswork; a plugin may still depend on custom metadata.
Choose a cleanup method that matches the risk
The right method depends on the size of the site and how comfortable you are recovering from a mistake. I use the dashboard for a few posts, WP-CLI for controlled bulk work, and direct SQL only when I have a verified recovery path.
Clean selected posts from the dashboard
For a small number of posts, open the content in the WordPress editor and use its Revisions panel. This is slow across hundreds of posts, but it gives you the clearest control when an editor has overwritten text or a product description needs to be compared with an older version.
Sometimes the safest method is the boring one.
Remove revisions with WP-CLI
If the goal is to remove every revision, check the backup before running the deletion. First list the IDs:
wp post list --post_type=revision --format=idsReviewing a sample of those IDs is worthwhile, especially on a site with custom post types. For a modest list, you can delete them with:
wp post list --post_type=revision --format=ids | xargs -r -n 100 wp post delete --forceThis uses the GNU/Linux form of xargs; -r prevents it from running when the list is empty, and -n 100 keeps the command in manageable batches. WP-CLI deletes each revision as a WordPress post, which also gives WordPress the opportunity to remove metadata associated with that revision.
On systems where xargs -r is unavailable, use a shell check instead:
ids=$(wp post list --post_type=revision --format=ids)
if [ -n "$ids" ]; then
wp post delete $ids --force
fiFor very large sites, I prefer the batched command. Shell command-length limits are an unnecessary failure mode.
My own mistake here was running a maintenance command from the wrong test directory because the shell prompt looked almost identical to the production one. I caught it before deletion, but now I verify the path with pwd and the site with wp option get siteurl first.
pwd
wp option get siteurl
wp post list --post_type=revision --format=ids | wc -wThese checks confirm the directory, the loaded WordPress site, and the number of IDs before you remove anything.
Use SQL only with a recovery plan
Direct SQL is fast and unforgiving. I use it only when I have a verified database export, restore access, and a clear reason not to use WP-CLI.
DELETE FROM wp_posts
WHERE post_type = 'revision';This removes revision rows from wp_posts; it does not remove normal posts, pages, or products. It can also leave metadata rows in wp_postmeta, depending on the data and the plugins installed. That is why I do not follow it with a broad, invented orphan-cleanup query.
Before running SQL on a live site, I export the affected rows or test the operation against a staging copy. A transaction can help with some database engines and workflows, but it is not a substitute for a backup, especially when a large delete causes locks or runs longer than expected.
Keep a limit instead of an unlimited backlog
For most sites, retaining a defined number of recent revisions is a better balance than disabling revisions entirely. Add this to wp-config.php, before the line that says That's all, stop editing!:
define( 'WP_POST_REVISIONS', 10 );This limits the number of stored revisions per piece of content from that point forward. It does not remove the revisions already in the database, so an existing backlog needs its own cleanup.
You can disable revisions with:
define( 'WP_POST_REVISIONS', false );I rarely choose that setting. If an editor changes a price or deletes a section by accident, the revision history may be the quickest recovery point. Five or ten revisions is a reasonable starting point for many sites, but an editorial team with formal approvals may need more.
Be careful while editing wp-config.php. I have seen a one-character syntax mistake turn a small configuration change into a 500 response. Make a copy first, edit the file carefully, and check the site immediately afterward.
Be selective with cleanup plugins
A dashboard plugin can make revision maintenance easier, but I check more than its list of cleanup options. I look at its update history, compatibility with the WordPress version running on the site, whether it offers a preview, and how easily I can undo its work.
Many cleanup plugins also offer to remove trashed posts, spam comments, transient options, and orphaned metadata. I do not select every checkbox by habit. A value that looks disposable may be configuration or cache data required by another plugin.
Run the first cleanup on staging if you have a usable staging copy. Test the homepage, several posts, the login form, the contact form, and the WooCommerce cart and checkout where applicable. Keep the backup until those checks pass.
To compare the main table sizes before and after the work, I use:
SELECT table_name,
ROUND(data_length / 1024 / 1024, 2) AS data_mb,
ROUND(index_length / 1024 / 1024, 2) AS index_mb
FROM information_schema.tables
WHERE table_schema = DATABASE()
AND table_name IN ('wp_posts', 'wp_postmeta');Change the table names to match your prefix. The data and index figures can fall without the operating-system file becoming smaller immediately; InnoDB may retain allocated space for reuse.
Why disk usage may not change straight away
This comes up often in support tickets. DELETE removes rows, but an InnoDB table does not necessarily return that physical space to the filesystem at once. The deletion may still have worked.
Check the remaining revisions before attempting an optimization:
wp db query "SELECT COUNT(*) AS revision_count FROM wp_posts WHERE post_type = 'revision';"If the count has fallen, the cleanup did what it was supposed to do. OPTIMIZE TABLE can rebuild a table and reclaim space in some MySQL and MariaDB configurations, but it may need considerable temporary disk space and can lock or disrupt access to a busy table.
OPTIMIZE TABLE wp_posts;Run that during a maintenance window, not while a busy WooCommerce store is processing orders. Check the exact database engine and table size first. If the site starts showing connection errors or damaged-table messages, follow the diagnostic order in WordPress Error Establishing a Database Connection: Fixes. Revision cleanup does not require changing DB_HOST or database credentials.
Automation needs a stop condition
A scheduled cleanup is useful only when I can tell whether it ran and whether it did something sensible. I monitor even my home cron jobs with Uptime Kuma on a Raspberry Pi. An unmonitored cron job is a cron job I am merely assuming works.
My preferred order is:
- Create a database backup.
- Confirm that the newest backup exists and has a plausible size.
- Count the revisions before cleanup.
- Delete only the records within the planned scope.
- Log the result and alert if the count is unexpectedly high.
Keep backups away from the same disk as the live database. A disk failure or an incorrect SQL command can make both unavailable together. The guidance in RPO, RTO and Disaster Recovery Planning for Small Businesses is useful when you are deciding how much backup history and recovery time your site actually needs.
If you write a script around WP-CLI, give it a threshold. For example, stop and notify me if the revision count suddenly jumps from a few thousand to several hundred thousand. That kind of change usually deserves investigation before deletion, not a larger broom.
Do not blame revisions for every slow WordPress site
The performance effect depends on the database, the queries, and the way the site is used. A small revision backlog may produce no measurable change. A large backlog can reduce backup time or help particular database and dashboard operations, but the result must be measured.
When a site is slow, revisions are not my first suspect. I check slow queries, PHP-FPM saturation, disk wait, object caching, plugin behavior, and external API calls. On WooCommerce sites, a reporting plugin or an unfiltered query often matters more than old revisions.
As I explain in Hosting and SEO: Myths vs Reality About IPs, Location, CDNs and HTTP/2/3, a cleaner database does not automatically improve rankings. Record your database size, backup duration, homepage response time, and the time required to save a post before and after maintenance. Your own measurements are more useful than a promise attached to a cleanup button.
Frequently asked questions
Is it safe to delete all WordPress revisions?
It is generally safe when you have a verified backup and no need for older versions. I still test the process on staging when possible, and I keep a defined number of revisions on sites with active editorial workflows.
Will revision cleanup delete my posts?
When the command is correctly limited to post_type = 'revision', published posts, pages, and products remain. Check the site URL, table prefix, query scope, and row count before deletion.
How many revisions should I keep?
Five or ten revisions per item is a reasonable starting point for many sites. Teams with several editors or approval stages may need a higher limit. The setting only controls future revisions; it does not clear the existing backlog.
Why did disk usage stay the same after cleanup?
InnoDB may retain the table’s allocated space even after rows are deleted. Confirm the remaining revision count first, then consider a table rebuild during a maintenance window with enough free disk space.
My order is simple: back up, verify the restore path, inspect a sample, and only then delete. I still keep revisions enabled. I just do not let an old safety net quietly become the largest object in the database.





