When WordPress Has Thousands of Spam Comments: Cleaning Up over SSH

2026-02-15

A few comments a day are easy to handle. Then you take a few days away and come back to thousands waiting for approval and thousands more already marked as spam. The public site may still load, while the comments screen hangs and even the dashboard takes longer than usual.

The obvious response is to select a page at a time and move the entries to the trash. That still asks the application to load and render the list for every batch. On a small instance, working through a large backlog that way can be impractical. If you see a database connection error, check the database service and logs before assuming the comment backlog is responsible.

On a self-managed site you can use SSH to inspect the backlog and clean it up without repeatedly opening the dashboard. The original cleanup used SQL to reach the comment tables directly. For routine work, prefer WordPress’s comment commands through WP-CLI so WordPress can maintain its metadata, counts and caches. The SQL notes below document what a direct cleanup entails.


1. Back up the database

Take a full database backup before changing anything and verify that it can be restored. The separate two-table export below was useful as a targeted copy of the comments and metadata. Replace the example database and table names with yours and keep the dump outside the web root.

mysqldump -u root -p bitnami_wordpress wp_comments wp_commentmeta > comments_backup.sql

The client prompts for the database password. Check that the dump finished without errors and that the output is readable. It can contain email addresses, IP addresses and other private data, so store it somewhere protected.


2. Connect to the database

Open the database client for the correct WordPress database. Use an account with only the access needed for your task. The command shown is the original Bitnami example. The executable and database name can differ between images.

mysql -u root -p bitnami_wordpress


A MariaDB prompt can look like this.

MariaDB [bitnami_wordpress]>

Commands at this prompt are SQL. Start with read-only checks.


3. Confirm the table prefix

WordPress often uses wp_ as a table prefix. Installations with a custom prefix or multiple sites can use different names.

SHOW TABLES;

Confirm the target site’s prefix in its configuration and check the table names. Use those names consistently in your commands, and make sure you are looking at the intended site.


4. Count the two queues

Record how many comments are pending and how many WordPress has already marked as spam. These counts describe two different queues.

Pending comments:

SELECT COUNT(*) FROM wp_comments WHERE comment_approved = '0';


Comments marked as spam:

SELECT COUNT(*) FROM wp_comments WHERE comment_approved = 'spam';

A big queue tells you how much work there is to review. Check the slow requests and database logs separately if you want to know whether the backlog is contributing to a performance problem.


5. Delete reviewed spam in batches

Review a sample of the spam queue first. Work on a copy or during a maintenance window, and keep legitimate comments in moderation for review.

List already-flagged spam from the WordPress directory in your shell, outside the SQL prompt. This example retrieves only the first hundred IDs.

wp comment list --status=spam --number=100 --format=ids


Delete only the reviewed IDs you supply. This example uses permanent deletion.

wp comment delete 123 456 --force


WP-CLI reports which IDs it processed.

Success: Deleted comment 123.
Success: Deleted comment 456.

The affected count depends on the number of IDs supplied. Verify the selected comments, work in bounded batches and check the result after each one. The example IDs are placeholders. Use permanent deletion only after you have confirmed the backup and the selection.


6. Check for leftover metadata after an older SQL cleanup

A direct SQL deletion from the comments table can leave orphaned metadata and bypass WordPress housekeeping. After using WordPress’s own comment deletion, a separate metadata cleanup generally should not be necessary. The read-only query below can inspect orphaned metadata after an older direct cleanup.

SELECT COUNT(*) FROM wp_commentmeta AS m
LEFT JOIN wp_comments AS c ON c.comment_ID = m.comment_id
WHERE c.comment_ID IS NULL;

If that count is unexpected, review the affected rows in a copy before making a further change. Also check whether there are stale comment counts or caches left from the earlier direct deletion.


7. Decide whether to optimize the tables

Deleted rows may leave free space that the database can reuse without shrinking the file. Optimizing a table can take locks, use extra disk space and affect other requests. Consider it only if there is a measured storage or maintenance need.

If optimization is warranted, verify free space, the storage engine and your version’s behavior, then schedule the work for a maintenance window.


8. Leave the database prompt

exit

After the cleanup

A backlog that overwhelms the dashboard is easier to inspect and process from the command line. The practical order is to back up, separate pending comments from confirmed spam, and use the application’s deletion command on a reviewed batch.

Afterward, compare dashboard and database behavior with your earlier measurements. If requests are still slow, the server logs can point to the next cause to investigate.

Search stories