Ahosting Logo
Knowledge Base

How to Stop Spam Registrations and Fake Accounts

The first question is whether registration should be openDoes this site need visitors to be able to register themselves?YesThen defend itapproval or verification, a challenge, and a rolewith minimal capabilitiesNoTurn it offthe setting is on by default on many installs andthe problem disappears entirelyMost sites drowning in fake accounts never intended to accept registrations, and switching it off is a checkbox.

A site accumulates hundreds or thousands of accounts nobody created deliberately. Before treating it as a spam problem, ask a simpler question.

Do you need registration at all?

Under Settings → General, "Anyone can register".

A large share of sites collecting fake accounts do not offer anything to registered users. The setting is on because it was on, and turning it off ends the problem completely, permanently, and at no cost.

Check what actually depends on it first. A shop needs customer accounts; a membership site needs registration; a brochure site with a contact form does not.

If nothing depends on it, this is the entire article.

Why they bother

Worth understanding, because it decides what to defend.

Some are looking for a profile field that renders a link on a public page. Some are testing whether the default role can do more than it should. Some are preparing for a later vulnerability, so the account exists in advance. Many are simply automated noise hitting every registration form they find.

Almost none of them are people.

If registration is genuinely needed

Require email confirmation. The account is created but unusable until a link is clicked. Automated registrations rarely complete it, and this alone removes most of the volume.

Confirm the mail actually sends before relying on it. A site that cannot send email turns this into a wall real users cannot pass either. Fixing WordPress email not sending goes into checking.

Add a challenge to the form. Ordinary automated sign-ups stop at the first one. Determined ones do not, but the volume is overwhelmingly ordinary.

Rate limit by address. Real people register once. An address producing twenty registrations in a minute is not a person, and this is agnostic about what the client claims to be. For the mechanism, see stopping bots and scrapers.

Check the default role

Also under Settings, General. It should be the least capable role that is useful: normally Subscriber.

A default of Contributor or above means fake accounts can create content, and a default of Administrator means the site is already lost. This is worth checking on any site you inherit, because it is occasionally set wrongly by a plugin and nothing announces it.

WordPress user roles and permissions goes into what each can do.

The registration form is not the only door

Comment forms, contact forms and any plugin that creates users on submission are all registration paths.

A site with registration disabled that still gains users has one of these, and finding it means looking at what creates accounts rather than at the registration setting. Checking when the accounts were created, and correlating with anything else happening at those times, usually identifies it.

Cleaning up existing accounts

Do not bulk delete without looking.

Sort users by registration date and read a sample. Fake accounts usually cluster in time, share address patterns, and have no activity. Real users can look similar: a genuine customer who registered and never returned looks identical to noise.

And deleting a user can take their content with it, or reassign it. On a store, a user with orders should not be deleted at all, because the orders reference them. There is more on which records must be kept in WooCommerce database growth.

Where the volume is large, deleting in batches is safer than one enormous operation, and a backup taken first is not optional.

The cost while it continues

Each registration attempt starts PHP, so a form under sustained automated attack consumes real processing, which on a shared plan is the resource that actually binds.

That is a second reason to close the door rather than to filter behind it. A request refused before the application starts costs a fraction of one that creates a user and then deletes it: monitoring your hosting resources goes over noticing the load, and securing WordPress deals with the rest of the exposed surface.

Measure what it is actually costing

The argument for acting is easier to make with the numbers, and they are in the database.

wp db query "SELECT DATE(user_registered) g, COUNT(*) FROM wp_users
  GROUP BY g ORDER BY g DESC LIMIT 14;"
wp db query "SELECT COUNT(*) FROM wp_users u
  LEFT JOIN wp_posts p ON p.post_author=u.ID
  WHERE p.ID IS NULL AND u.user_registered < DATE_SUB(NOW(), INTERVAL 30 DAY);"

Registrations per day tells you whether this is background noise or an active campaign. Accounts that have never done anything tells you how many of the total are real.

On many sites the second figure is most of the first, which reframes the question from whether to act to why registration is open at all.

Remove the accounts carefully

Bulk deletion is the obvious response and it is the step where real customers get removed alongside the rest.

wp user list --role=subscriber --field=ID --number=5 | head
wp db query "SELECT COUNT(*) FROM wp_users u JOIN wp_usermeta m ON m.user_id=u.ID
  WHERE m.meta_key='wp_capabilities' AND m.meta_value LIKE '%subscriber%';"

Export the list before deleting anything, and check whether any of them have orders, comments or anything else attached. Deleting a user with content attached either removes the content or orphans it, depending on how the deletion is performed.

Work in small batches and confirm the count after each. A deletion that runs over thousands of records can time out partway, leaving a state that is harder to reason about than either the start or the end.

Close the other routes in

Turning off the registration form addresses one door, and automated systems use several.

curl -sI https://example.com/wp-login.php?action=register | head -1
curl -sI https://example.com/xmlrpc.php | head -1
awk '$7 ~ /register|signup|xmlrpc/ {print $7}' ~/logs/example.com | sort | uniq -c | sort -rn | head

The interface used by applications can create accounts where the site permits it, and a form provided by a plugin has its own address that the main setting does not cover.

Read the log for what is actually being requested rather than assuming. The addresses receiving traffic are the ones that need attention, and they are frequently not the ones anybody thought of. Securing the REST API and XML-RPC covers the rest.