
If you watch your server logs for even a day, you will see it: a steady drip of POST requests to /wp-login.php, often from rotating IPs, often trying usernames like admin and passwords pulled from old breach dumps. This is credential stuffing and brute forcing, and it is automated, cheap, and constant. No single plugin stops it. What works is layering defenses so that even if one layer fails, the attacker still does not get in.
Why wp-login Gets Hammered
WordPress powers a huge share of the web, its login endpoint is predictable, and its authentication cookie scheme is well documented. Attackers do not need to target you specifically. They run lists of leaked credentials against thousands of login pages hoping a small percentage match reused passwords. That is credential stuffing. Separately, pure brute force tools guess common passwords against known usernames. Both are volume plays, and both are beatable with the right layers.
Layer 1: Make Stolen Credentials Worthless
The most effective single control is two factor authentication (2FA) on every account with publish or admin capabilities. Even if a password leaks or gets guessed, a time based one time password (TOTP) code from an authenticator app stops the login cold. Enforce 2FA for administrators and editors at minimum, not just as an option users can ignore.
Pair this with actually unique, generated passwords stored in a password manager, not variations on a theme. Audit your user list periodically with wp-cli:
wp user list --fields=ID,user_login,user_email,rolesLook for accounts that should not exist anymore (old contractors, test accounts, a second admin nobody remembers creating). Remove or demote them:
wp user delete 42 --reassign=1
wp user update 17 --role=subscriberLeast privilege matters here. A user who only writes posts should be an Author or Editor, not an Administrator. Fewer high privilege accounts means fewer high value targets.
Layer 2: Slow Down and Lock Out Automated Attempts
Rate limiting login attempts is what turns an unlimited guessing game into a losing one for the attacker. After a handful of failed attempts from an IP or against a username, that source should be locked out for a period of time, with the lockout window increasing on repeat offenses. This is standard functionality in most login security plugins, and it is one of the highest value, lowest friction controls you can add.
If you manage your own server, you can enforce similar limits below WordPress entirely, for example with fail2ban watching your web server or PHP-FPM logs for repeated failed login patterns and banning the IP at the firewall. That stops the requests from even reaching PHP, which is cheaper for your server under sustained attack.
On a managed LiteSpeed stack, some of this workload gets absorbed before it ever taxes your database, since full page caching and connection handling reduce how much a login flood actually costs you in resources, even while the security layer above still needs to do the blocking.
Layer 3: Bot Challenges and CAPTCHAs
A CAPTCHA on the login form filters out unsophisticated scripted attempts without bothering real users much. It is not a complete solution on its own (CAPTCHA solving services exist), but as one layer among several it meaningfully thins the herd.
The bigger lever here is putting Cloudflare in front of your site. Its web application firewall (WAF) and bot mitigation can challenge or block suspicious traffic before it ever reaches your origin server, based on signals like request patterns, reputation, and behavior, not just a single form field. Combined with keeping your origin server’s IP address unpublished, this also removes the option for attackers to bypass your edge defenses entirely and hit the server directly, which matters for both login abuse and broader DDoS resilience.
Layer 4: Shrink the Attack Surface
Several small changes reduce what is exposed in the first place:
- Disable XML-RPC if you do not use it. It has historically been abused for amplified brute force attempts (a single request can test many password combinations) and pingback abuse. If you do not rely on the mobile app or remote publishing tools that need it, turn it off.
- Set DISALLOW_FILE_EDIT. This removes the built-in theme and plugin file editor from wp-admin, so a compromised admin session cannot be used to drop a web shell through the dashboard editor:
wp config set DISALLOW_FILE_EDIT true --raw- Consider a non-default login path. Moving the login form off the well known URL will not stop a targeted attacker, but it does quietly filter out a large share of dumb, automated scanning that only checks the default path. Treat it as noise reduction, not a real security boundary.
- Keep core, plugins, and themes updated. Many login and privilege escalation issues trace back to outdated code with known fixes already available.
Layer 5: Assume Something Gets Through
Layered defense reduces risk, it does not eliminate it. Tested, off-site backups are the layer that matters when everything else fails. A backup you have never restored is a hope, not a plan. Periodically test a full restore to a staging environment so you know it actually works and how long it takes.
Also watch your logs, not just for logins, but for new user creation, plugin installs, and file changes you did not initiate. wp-cli makes a quick user audit trivial to run on a schedule:
wp user list --role=administrator --fields=ID,user_login,user_registeredSet a reminder to review this monthly. Catching an unexpected administrator account early is far cheaper than cleaning up after it has been used.
Putting It Together
- Enforce 2FA for every account above Subscriber level.
- Require unique, generated passwords via a password manager.
- Add login rate limiting with escalating lockouts.
- Put Cloudflare (or an equivalent WAF and bot mitigation layer) in front of the origin, and keep the origin IP unpublished.
- Add a CAPTCHA to the login form as an extra filter, not your only defense.
- Disable XML-RPC if unused, and set DISALLOW_FILE_EDIT.
- Audit users and roles monthly with wp-cli.
- Maintain tested, off-site backups and verify restores periodically.
The Takeaway
No single control stops credential stuffing or brute force attacks against wp-login.php. What works is stacking cheap, independent layers so that a failure in one does not mean a compromise: strong unique credentials backed by 2FA, rate limits that punish repeated guessing, a WAF and bot mitigation in front of your origin, a smaller attack surface, and backups you have actually tested. None of this is exotic. It is disciplined, and it is what separates sites that shrug off automated attacks from the ones that end up rebuilding from scratch.