Every time you hit “Save Draft” or “Update” in WordPress, the system silently stores a complete copy of your content as a post revision. On a site with hundreds of posts edited frequently, this adds up fast — bloating your wp_posts table with thousands of unnecessary rows that slow down queries, inflate database backups, and waste storage.
This guide covers three practical approaches to taming WordPress post revisions: limiting how many are kept, disabling them entirely, and cleaning up existing revision bloat safely. We will use wp-config.php constants, PHP filters, raw SQL, and WP-CLI — with safety warnings at every step. If you are working through a broader WordPress maintenance checklist, revision management should be near the top of your list.
How WordPress Post Revisions Work
WordPress stores revisions as rows in the wp_posts table with a post_type of revision. Each revision is a child of its parent post, linked via the post_parent column. WordPress also creates autosaves — a special single revision that gets overwritten every 60 seconds while you edit.
Here is a quick breakdown of how revisions accumulate:
- Every “Update” click creates one new revision row
- Autosaves are stored separately (one per post, overwritten)
- No default limit — WordPress stores unlimited revisions out of the box
- Revisions are never auto-deleted — they persist until you remove them
To see how many revisions your database currently holds, run this SQL query in phpMyAdmin or your database client:
SELECT COUNT(*) FROM wp_posts WHERE post_type = 'revision';
If that number is in the thousands — or tens of thousands — it is time to act.
Understanding the Performance Impact
Post revisions affect WordPress performance in several measurable ways:
- Database size: Each revision duplicates the full
post_contentfield. A 2,000-word post with 50 revisions stores 100,000+ words of redundant content in your database. - Query performance: Queries against
wp_postsscan more rows. Thewp_postmetatable also grows because each revision can carry its own meta entries. - Backup size and duration: Larger databases take longer to back up and restore. For sites on shared hosting with limited storage, this directly impacts costs and reliability.
- Admin editor slowdowns: The block editor loads revision data. Posts with 100+ revisions can noticeably slow down the editing experience, especially on resource-constrained servers.
Cleaning up revisions on a database with 50,000+ revision rows can reduce the wp_posts table size by 40-60% and improve query response times measurably. The exact gains depend on your average post length and how many revisions each post carries.
Method 1: Limit Post Revisions via wp-config.php
The simplest and most widely recommended approach is setting the WP_POST_REVISIONS constant in your wp-config.php file. This tells WordPress the maximum number of revisions to keep per post going forward.
Setting a Revision Limit
Open your wp-config.php file (located in the WordPress root directory) and add this line before the /* That's all, stop editing! */ comment:
// Keep only the 5 most recent revisions per post
define( 'WP_POST_REVISIONS', 5 );
Here is what different values do:
| Value | Behavior |
|---|---|
true (default) | Unlimited revisions — WordPress default |
false or 0 | Disables revisions completely (autosaves still work) |
5 | Keeps the 5 most recent revisions per post |
10 | Keeps the 10 most recent revisions per post |
-1 | Unlimited revisions (same as true) |
Recommended value for most sites: 3 to 5. This preserves enough history to recover from accidental edits while keeping the database lean.
WP_POST_REVISIONS only affects future saves. Existing revisions beyond the limit are not automatically deleted. You need to clean those up separately (covered in Method 3 below).
Disabling Revisions Entirely
If you do not need revision history at all — for example, on a site where content is managed through version control or staging workflows — you can disable revisions completely:
// Disable post revisions entirely
define( 'WP_POST_REVISIONS', false );
Or equivalently:
define( 'WP_POST_REVISIONS', 0 );
Method 2: Fine-Grained Control with the wp_revisions_to_keep Filter
The wp_revisions_to_keep filter gives you programmatic, per-post-type control over revision limits. This is more flexible than the wp-config.php constant because you can set different limits for different content types.
Basic Usage
Add this to your theme’s functions.php or — better — a custom site-specific plugin:
/**
* Limit revisions to 3 for all post types.
*
* @param int $num Number of revisions to keep.
* @param WP_Post $post The post object.
* @return int
*/
add_filter( 'wp_revisions_to_keep', function( $num, $post ) {
return 3;
}, 10, 2 );
Per-Post-Type Limits
This is where the filter becomes genuinely useful. You can keep more revisions for high-value content (like landing pages) and fewer for less critical types:
add_filter( 'wp_revisions_to_keep', function( $num, $post ) {
$limits = array(
'post' => 3, // Blog posts: 3 revisions
'page' => 10, // Pages: 10 revisions (more critical content)
'product' => 5, // WooCommerce products: 5 revisions
);
if ( isset( $limits[ $post->post_type ] ) ) {
return $limits[ $post->post_type ];
}
return 3; // Default for all other post types
}, 10, 2 );
Disable Revisions for Specific Post Types Only
If you want revisions for posts and pages but not for a custom post type like event:
add_filter( 'wp_revisions_to_keep', function( $num, $post ) {
if ( 'event' === $post->post_type ) {
return 0; // No revisions for events
}
return $num; // Keep default for everything else
}, 10, 2 );
wp_revisions_to_keep filter takes priority over the WP_POST_REVISIONS constant. If both are set, the filter wins. This is documented in the WordPress Developer Reference.
Method 3: Clean Up Existing Revisions Safely
Limiting future revisions is only half the battle. If your site has been running for months or years without revision limits, thousands of stale revisions are sitting in the database right now. Here is how to remove them safely.
Step 1: Back Up Your Database First
This step is non-negotiable. Before running any deletion query, create a full database backup:
# Using WP-CLI (recommended)
wp db export backup-before-revision-cleanup.sql
# Using mysqldump directly
mysqldump -u db_username -p db_name > backup-before-revision-cleanup.sql
Verify the backup file exists and has a reasonable file size before proceeding. A database with 50,000 posts should produce a backup file at least a few hundred megabytes in size.
Step 2: Check Current Revision Count
# Count all revisions via WP-CLI
wp post list --post_type=revision --format=count
# Or via SQL
wp db query "SELECT COUNT(*) as revision_count FROM wp_posts WHERE post_type = 'revision';"
Write down this number so you can verify the cleanup worked.
Step 3: Delete Revisions with WP-CLI (Recommended Method)
WP-CLI is the safest cleanup method because it triggers proper WordPress hooks and automatically cleans up associated metadata:
# Delete ALL revisions
wp post delete $(wp post list --post_type=revision --format=ids) --force
# Delete revisions older than 30 days only
wp post list --post_type=revision --format=ids --before="30 days ago" | xargs wp post delete --force
For sites with very large numbers of revisions (10,000+), process them in batches to avoid memory exhaustion:
# Delete revisions in batches of 500
while ids=$(wp post list --post_type=revision --format=ids --posts_per_page=500); do
if [ -z "$ids" ]; then
break
fi
wp post delete $ids --force
echo "Deleted batch. Remaining: $(wp post list --post_type=revision --format=count)"
sleep 1
done
Step 4: Delete Revisions with Raw SQL (Faster, Riskier)
For databases with 50,000+ revisions where WP-CLI is too slow, direct SQL queries are significantly faster. However, SQL bypasses WordPress hooks entirely, so you must also clean up orphaned data manually.
-- Step 4a: Delete all revision posts
DELETE FROM wp_posts WHERE post_type = 'revision';
-- Step 4b: Clean up orphaned postmeta (meta for deleted posts)
DELETE pm FROM wp_postmeta pm
LEFT JOIN wp_posts p ON p.ID = pm.post_id
WHERE p.ID IS NULL;
-- Step 4c: Clean up orphaned term relationships
DELETE tr FROM wp_term_relationships tr
LEFT JOIN wp_posts p ON p.ID = tr.object_id
WHERE p.ID IS NULL;
wp_ with your actual table prefix if you have changed it from the default. You can find your prefix in wp-config.php under the $table_prefix variable. Running these queries with the wrong prefix will either do nothing or — worse — delete data from unrelated tables.
If your database is extremely large, delete in batches to avoid locking the table for too long:
-- Delete 5,000 revisions at a time
DELETE FROM wp_posts WHERE post_type = 'revision' LIMIT 5000;
Run this query repeatedly until it reports 0 affected rows.
Step 5: Optimize Database Tables
After deleting thousands of rows, MySQL retains the allocated disk space. Run an optimize command to reclaim it:
# Via WP-CLI
wp db optimize
# Via SQL
OPTIMIZE TABLE wp_posts, wp_postmeta, wp_term_relationships;
On large tables, this operation can take several minutes. Run it during low-traffic hours.
Method 4: Reduce Autosave Frequency
While autosaves do not pile up like revisions (WordPress keeps only one autosave per post, overwriting it each time), the default 60-second interval generates frequent database writes on busy multi-author sites. You can increase the interval:
// Autosave every 3 minutes instead of every 60 seconds
define( 'AUTOSAVE_INTERVAL', 180 );
Add this to wp-config.php alongside your revision settings. A value between 120 and 300 seconds is reasonable for most sites. Do not set it too high — autosaves exist to protect against browser crashes and accidental tab closures.
Complete wp-config.php Configuration Block
Here is a ready-to-use configuration block that combines all the settings covered above. Drop this into your wp-config.php file before the “stop editing” comment:
/**
* Database Optimization: Revisions & Autosaves
*/
// Limit post revisions to 5 per post
define( 'WP_POST_REVISIONS', 5 );
// Increase autosave interval to 3 minutes (180 seconds)
define( 'AUTOSAVE_INTERVAL', 180 );
Automating Revision Cleanup with WP-Cron
For sites that need ongoing maintenance without manual intervention, you can schedule periodic revision cleanups using the WordPress cron system. Add this to a site-specific plugin (not functions.php — theme switches would remove it):
<?php
/**
* Plugin Name: TweaksWP Revision Cleanup
* Description: Automatically cleans up old post revisions weekly.
* Version: 1.0.0
*/
// Schedule the cleanup event on plugin activation
register_activation_hook( __FILE__, function() {
if ( ! wp_next_scheduled( 'tweakswp_cleanup_revisions' ) ) {
wp_schedule_event( time(), 'weekly', 'tweakswp_cleanup_revisions' );
}
});
// Unschedule on deactivation
register_deactivation_hook( __FILE__, function() {
wp_clear_scheduled_hook( 'tweakswp_cleanup_revisions' );
});
// The cleanup callback
add_action( 'tweakswp_cleanup_revisions', function() {
global $wpdb;
// Delete revisions older than 30 days, in batches of 1000
$deleted = $wpdb->query(
"DELETE FROM {$wpdb->posts}
WHERE post_type = 'revision'
AND post_date < DATE_SUB( NOW(), INTERVAL 30 DAY )
LIMIT 1000"
);
// Clean up orphaned postmeta
$wpdb->query(
"DELETE pm FROM {$wpdb->postmeta} pm
LEFT JOIN {$wpdb->posts} p ON p.ID = pm.post_id
WHERE p.ID IS NULL
LIMIT 1000"
);
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
error_log( sprintf(
'TweaksWP Revision Cleanup: Removed %d old revisions.',
$deleted
));
}
});
This approach uses $wpdb with the correct table prefix automatically, making it safe across different WordPress installations.
Verifying Your Changes Worked
After implementing any of these methods, verify that your changes are working correctly:
Check Remaining Revision Count
# Total revision count
wp post list --post_type=revision --format=count
# Top 10 posts with the most revisions
wp db query "SELECT post_parent, COUNT(*) as rev_count
FROM wp_posts
WHERE post_type = 'revision'
GROUP BY post_parent
ORDER BY rev_count DESC
LIMIT 10;"
Compare Database Size Before and After
# Full database table sizes
wp db size --tables --human-readable
# Just the wp_posts table
wp db query "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 = 'wp_posts';"
Test the Revision Limit Is Active
- Edit any post and click “Update” 6-7 times (making small changes each time)
- Open the “Revisions” panel in the post editor sidebar
- You should see only 5 revisions listed (if you set the limit to 5)
- The oldest revisions beyond the limit should have been automatically pruned
Plugin Alternatives for Non-Coders
If you prefer a GUI-based approach or you manage a multisite network where editing wp-config.php on every installation is impractical, these plugins handle revision management without code changes:
- WP-Sweep — Lightweight cleanup tool by Lester Chan. Cleans revisions, auto-drafts, orphaned metadata, and more with one click. Uses proper WordPress deletion functions.
- WP-Optimize — Full database optimization suite. Handles revisions plus table optimization, image compression, and caching. Good all-in-one option.
- Advanced Database Cleaner — Granular control with scheduling. Lets you clean specific revision groups and set automated cleanup schedules.
That said, the manual methods described in this guide give you complete control with zero plugin overhead. For a single site, wp-config.php constants plus occasional WP-CLI cleanup is the most efficient approach.
Troubleshooting Common Issues
Revisions Still Being Created After Setting WP_POST_REVISIONS to 0
A plugin or theme may be overriding the constant via the wp_revisions_to_keep filter. Debug with this snippet:
add_action( 'init', function() {
$post = get_post( 123 ); // Replace with a real post ID
if ( $post ) {
$keep = wp_revisions_to_keep( $post );
error_log( 'Revisions to keep for post 123: ' . $keep );
}
});
If the logged value is not 0, something is overriding your setting. Check active plugins — some page builders and revision-management plugins apply their own filters.
WP_POST_REVISIONS Constant Has No Effect
The constant must be defined before WordPress loads its core files. Make sure it appears in wp-config.php above this line:
/* That's all, stop editing! Happy publishing. */
If it is placed after require_once ABSPATH . 'wp-settings.php';, WordPress has already loaded and the constant is ignored.
SQL Query Times Out on Large Databases
If your DELETE query times out, process in smaller batches and add a brief pause between runs:
# Bash loop for batched SQL deletion
while true; do
result=$(wp db query "DELETE FROM wp_posts WHERE post_type = 'revision' LIMIT 5000;" 2>&1)
echo "$result"
# Check if no rows were affected
if echo "$result" | grep -q "0 rows"; then
echo "Cleanup complete."
break
fi
sleep 2
done
Summary and Recommended Configuration
For most WordPress sites, this combination delivers the best balance of safety and performance:
- Set
WP_POST_REVISIONSto 5 inwp-config.php— enough history for recovery, lean enough for performance - Use the
wp_revisions_to_keepfilter if you need different limits per post type - Clean up existing revisions with WP-CLI for safety, or raw SQL for speed on very large databases
- Optimize tables after cleanup with
wp db optimize - Set
AUTOSAVE_INTERVALto 180 to reduce unnecessary database writes - Schedule periodic cleanups via WP-Cron or a maintenance plugin for ongoing hygiene
Post revisions are a genuinely useful safety feature — they have saved countless hours of lost work. But left unchecked, they silently degrade database performance over months and years. A few minutes of configuration gives you the best of both worlds: content recovery when you need it, and a clean, fast database the rest of the time.
This is article 2 of 8 in our Database Optimization series on TweaksWP. Next up: cleaning orphaned postmeta and expired transients.
database cleanup post revisions wp_posts table WP-CLI wp-config.php
Last modified: February 16, 2026