WordPress brute-force attacks: wp-login.php, xmlrpc.php and how to stop them
In short
If your WordPress site gets thousands of login attempts on wp-login.php or xmlrpc.php, it is an automated brute-force attack: it happens to almost every site and does not mean anyone got in. You stop it with long, unique passwords, two-factor authentication for administrators (WordPress does not include it out of the box), rate limiting on the server or firewall and, if nothing of yours uses XML-RPC, blocking xmlrpc.php. The real danger is an administrator with a weak or reused password: then the attack can actually work.
An alert from your security plugin with hundreds of failed logins, an email from your hosting provider because the site is using too many resources, or a line in a scan saying "xmlrpc.php enabled". They all point to the same thing: bots trying passwords against your WordPress site, day and night. It looks scary, but it is one of the easiest things to stop. This guide explains what is going on, how to confirm it in your logs and what to change, in that order.
By Jose SorianoLast updated: 5 min read
What a brute-force attack is
It is a program that tries username and password combinations, one after another, until it gets one right. It is not after your site in particular: it works through thousands of WordPress sites at once from many different addresses. That is why almost every site gets it, and why the defense is not hiding, but making a correct guess impossible.
The two entry points are always the same:
wp-login.php, the normal login screen.xmlrpc.php, an old interface for publishing from external apps. It is a common target because it accepts many password attempts in a single request (thesystem.multicallmethod), so the attack goes faster and per-request attempt limits do not see it.
How to tell if you are getting one
If you have a security plugin, its failed-login log shows it. If not, check the server access log (in the hosting control panel it is usually called "Logs" or "Raw Access Logs"). With SSH access, these commands only read and count:
# How many POST requests have reached each file
grep -c "POST /wp-login.php" access.log
grep -c "POST /xmlrpc.php" access.log
# Which addresses send the most attempts
grep -E "POST /(wp-login|xmlrpc)\.php" access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -20Hundreds or thousands of requests a day from many addresses is the typical pattern. What would be serious is a successful dashboard login from an address or country you do not recognize, or a new administrator nobody created. If you see that, it is not just an attempt: follow the guide on how to tell if your WordPress site is hacked.
The free scan checks from the outside whether xmlrpc.php responds, whether the site exposes usernames and whether the login screen has any rate limit.
What stops it, in order of importance
1. Long, unique passwords
This is what decides whether the attack works. A long password, generated by a password manager and not used anywhere else, will not be guessed by a bot. Pay most attention to administrators and old editor accounts: the account of the agency that built the site, the one of an employee who has left. Delete the ones nobody uses, or lower their role.
2. Two-factor authentication for administrators
WordPress does not include it out of the box. A plugin adds it: the free Two Factor plugin, maintained by WordPress contributors, or the one built into Wordfence and Solid Security. With a code from an app on your phone, even someone who guesses the password cannot log in. Turn it on at least for every account with the administrator role.
3. Rate limiting, ideally outside WordPress
A security plugin can block an address after a few failures, and that is enough for most sites. But every attempt still reaches PHP. If the attack is heavy, the limit works better earlier: in your CDN's or hosting provider's firewall, or on the server itself. The WordPress documentation suggests, for example, limiting requests to wp-login.php and xmlrpc.php in Nginx with limit_req.
4. Block xmlrpc.php if you do not use it
Hardly anything needs it today, but before blocking it, make sure nothing of yours uses it: Jetpack, a mobile app or an external service that publishes to your site. If you use it, limit it rather than block it. If not, on Apache (in the .htaccess in the site root):
<Files xmlrpc.php>
Require all denied
</Files>On Nginx, inside the site's server block:
location = /xmlrpc.php {
deny all;
}There is a third option you will see in many tutorials: the xmlrpc_enabled filter. Careful, because despite its name it does not turn XML-RPC off entirely: it only disables the methods that require a username and password. It cuts brute force through that route, but the file still responds (to pingbacks, for example). If you want to close it completely, the server rule is cleaner.
5. Do not expose usernames
Once the username is guessed, the attacker only needs the password. Many WordPress sites show the login name on author pages or in the REST API. The simplest fix is to make the public name different from the login name: in Users → Profile, fill in the nickname and pick a different one under "Display name publicly as". And never use admin as a username. This helps, but it does not replace points 1 and 2.
6. Application passwords for integrations
If an external service needs to publish to your site, use an application password (in your user profile, since WordPress 5.6) instead of your real password. You can revoke it at any time without touching your own login.
If you suspect someone got in
- Change the password of every administrator from a clean computer.
- Regenerate the security keys in
wp-config.php: this logs out every open session. - Go through Users, filter by administrator and delete anything you do not recognize.
- Check plugins,
.phpfiles inuploadsand redirects, using the guide on how to tell if your WordPress site is hacked.
If you find something, hacked WordPress cleanup costs €219 (excluding VAT), with a 90-day guarantee. If you just want the logins properly locked down (two-factor authentication, users, xmlrpc.php and limits), that is part of the hardening in WordPress security, and with WordPress maintenance I check it every week.
Sources
- WordPress: brute force attacks (xmlrpc.php and
system.multicallas a common target, 2FA not included in core, rate limiting on the server or firewall, and examples for Apache and Nginx). - WordPress: the xmlrpc_enabled filter (it only controls the methods that require authentication, not pingbacks).
- WordPress: application passwords integration guide (WordPress 5.6, revocable one by one).
- Two Factor plugin on WordPress.org (app codes, email and backup codes).
- Apache: access control (
Require all denied) and nginx: access module (deny all). - OWASP: brute force attack.
Frequently asked questions
What is xmlrpc.php and should I disable it?
It is an old WordPress interface for publishing from external apps. If nothing of yours uses it (Jetpack, an app or a service that publishes to your site), block it on the server: it is a common brute-force target. If you do use it, rate-limit it instead of blocking it.
I am getting hundreds of failed login attempts. Have I been hacked?
Not necessarily: it is an automated attack that almost every WordPress site gets. A successful login from somewhere you do not recognize, or a new administrator nobody created, would be serious.
Is the xmlrpc_enabled filter enough?
It stops password attempts through XML-RPC, but it does not turn the file off: pingbacks keep working. To close it completely, block xmlrpc.php in Apache or Nginx.
Does WordPress come with two-factor authentication?
No. You have to add it with a plugin, such as Two Factor (free) or the one included in Wordfence and Solid Security.
Does changing the wp-login.php URL help?
It cuts the noise in your logs, but it does not protect you if passwords are weak. It is an extra on top of two-factor authentication, not a replacement.