WP-Login Brute Force Attack: Am I Being Hacked?
By Glenn Lyvers · Updated · 7 min read
Thousands of POST requests to wp-login.php or xmlrpc.php in your logs almost always means you are being brute-forced, not that you have been hacked. Automated bots try username and password combinations against every WordPress site they can find, all day, and yours is simply on the list. The attack becomes a compromise only if one of those guesses works — and you can check for that in about ten minutes.
Is it an attack, or just background noise?
Both, usually. Every public WordPress site gets login attempts. What changes is the volume and whether anything behind it succeeds. A few hundred failed attempts a day from scattered IPs is background radiation: it has been happening since the day you launched and will keep happening after you fix everything. A sudden jump to tens of thousands of requests an hour, from hundreds of addresses at once, is a distributed campaign — still automated, still not targeted at you personally, but heavy enough to slow a small server to a crawl.
People usually find out one of three ways: a security plugin starts emailing lockout notices, the host sends a CPU or resource-limit warning, or the site gets slow and someone looks at the access log. None of those tells you whether a login got through. That takes a separate check.
What the log lines actually tell you
Open your raw access log (cPanel usually keeps it under ~/logs/ or via the Raw Access icon) and search for the login endpoints. A brute-force attempt looks like this:
203.0.113.45 - - [27/Sep/2026:03:14:07 +0000] "POST /wp-login.php HTTP/1.1" 200 4521 "-" "Mozilla/5.0 ..."
198.51.100.9 - - [27/Sep/2026:03:14:07 +0000] "POST /xmlrpc.php HTTP/1.1" 200 403 "-" "Mozilla/5.0 ..."
The status code is the useful part. On wp-login.php, a failed login returns 200 — WordPress redraws the login form with an error. A successful login returns a 302 redirect to /wp-admin/. So the line you are hunting for is a POST /wp-login.php with a 302, from an IP you don’t recognize, followed shortly by GET /wp-admin/ requests from the same address. xmlrpc.php is harder to read because it answers 200 either way; there the tell is what that IP did next.
Count the sources too: grep "POST /wp-login.php" access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head gives you the top offenders in one line. My guide to reading access logs after a hack goes further into separating bots from the one request that matters.
Did a login succeed? Four checks
- Users. In
Users → All Users, filter by Administrator. Better, runwp user list --role=administrator, because some malware hides admin accounts from the dashboard list. Anything you didn’t create is a compromise, full stop — see hidden admin users. - Sessions. Active sessions live in the
session_tokensrow ofwp_usermetafor each user, with the login IP and time. An admin session from an unfamiliar IP is the clearest evidence you will get. - Recent changes. New plugins, a theme file edited through the dashboard editor, a changed site or admin email. Attackers who get in through a guessed password go straight for the plugin uploader.
- Files. Anything modified in the last few days under
wp-content:find wp-content -type f -mtime -7 -name "*.php".
If all four come back clean, the attack failed and you have a hardening job, not a cleanup. If any of them turns something up, stop tuning your login page and treat it as a compromised site — start with what to do first and rotate every credential the attacker could have seen.
What actually stops it
Here is what works, in the order I would do it:
- Two-factor authentication on every administrator. This single change turns a correct password guess into a dead end. It is the most valuable thing on this list.
- Unique, long passwords, and no account called
admin. Bots tryadmin, the site name and any username they can enumerate from author archives first. Review who actually needs admin at all — my user access and permissions guide covers pruning roles. - Rate limiting before WordPress runs. Blocking at the web server, the host’s firewall, fail2ban or a WAF costs almost nothing. Blocking inside a PHP plugin still means every attempt boots WordPress and hits the database, which is why a plugin can stop the guesses and still leave the server overloaded.
- Disable XML-RPC if nothing uses it.
xmlrpc.phplets one request try many passwords throughsystem.multicall. The Jetpack app and some mobile publishing tools need it; most sites don’t. The xmlrpc.php guide explains how to check and how to turn it off without breaking anything that depends on it. - Put a WAF in front, and lock the origin. A proxy firewall absorbs the traffic before it reaches you — but only if attackers can’t go around it to your server’s real IP. Hacked despite Cloudflare covers that gap.
What isn’t worth the effort
Renaming wp-login.php to a secret URL cuts log noise, which is pleasant, but it is not a security control: xmlrpc.php still accepts logins, the new path leaks through redirects and plugins, and it has locked more owners out of their own sites than it has stopped attackers. Blocking individual IPs by hand is equally futile against a botnet with thousands of addresses. And CAPTCHA on the login form helps against humans, not against bots that go straight to XML-RPC or the REST API.
Also be careful with aggressive country blocking and lockouts. I regularly get calls from owners who locked themselves out with their own security plugin mid-panic. If that has happened, locked out of WordPress admin walks through getting back in safely.
Don’t want to watch for this yourself?
Most reinfections come from updates nobody applied and accounts nobody reviewed. That is exactly what a maintenance plan covers.
Not sure which? Ask me first — I’ll tell you honestly if you can handle it yourself.
Why it slows the whole site down
Each login attempt is a full PHP request: WordPress loads, connects to the database, hashes the submitted password and renders a page. Ten thousand of those an hour on shared hosting is enough to hit your account’s CPU or process limits, and when that happens real visitors get 503 errors or a site that takes ten seconds to load. That is often the first symptom people notice, and it is why hosts sometimes throttle or suspend an account under a brute-force wave even though nothing was compromised. If slowness is the problem and the logs show something other than login floods, malware making a website slow covers the other usual causes.
When it stops being a DIY job
If the checks above found an unknown admin, a successful 302 from a foreign IP, or new PHP files, the brute force is no longer the problem — whatever they installed after logging in is. Password changes alone won’t remove a backdoor they left behind, and that is the point where a proper malware cleanup pays for itself. If you only want a second opinion on whether the attack got through, a $19.95 inspection answers that, and the fee is credited toward a cleanup if one turns out to be needed. And if you would rather not be the one watching the logs, keeping the updates, two-factor and scans going is what my maintenance plans are for. You can also run a quick first check with the free site scanner.
Common questions
Does a brute force attack mean my WordPress site is hacked?
No. A brute force attack is an attempt, and almost every WordPress site receives them constantly. It only becomes a hack if one of the guesses succeeds. Check for unknown administrator accounts, admin sessions from unfamiliar IPs, POST requests to wp-login.php that returned a 302 redirect, and recently modified PHP files. If all of those are clean, the attack failed.
How do I stop thousands of wp-login.php requests?
Rate-limit or block them before WordPress loads, at the server firewall, with fail2ban, or through a web application firewall. Then enable two-factor authentication for every administrator and disable xmlrpc.php if nothing on the site uses it. A security plugin alone blocks the guesses but still lets each request consume server resources.
Should I rename wp-login.php?
It reduces log noise but it is not real protection. Attackers can still log in through xmlrpc.php and sometimes the REST API, the hidden URL tends to leak, and renaming the login page is one of the most common ways owners lock themselves out. Two-factor authentication and server-level rate limiting do far more for security.
Why are bots attacking my small website?
Because they attack every website. Brute force campaigns are automated and indiscriminate: botnets scan the internet for WordPress installations and try common usernames and leaked passwords against all of them. Being targeted says nothing about how important or visible your site is, only that it runs WordPress and is online.
Is xmlrpc.php brute force worse than wp-login.php?
It can be, because the system.multicall method lets one request test many passwords, so rate limits that count requests undercount the real number of guesses. It also returns status 200 whether a login succeeds or fails, which makes the logs harder to read. If nothing on your site needs XML-RPC, disabling it removes the problem entirely.
Can a brute force attack take my site offline?
Yes. Each attempt is a full PHP and database request, so a large campaign can exhaust CPU or process limits on shared hosting and cause slow pages or 503 errors for real visitors. Some hosts will throttle or suspend an account under heavy load even when nothing was compromised. Blocking at the server or WAF level prevents that.
More than malware
Most people meet me in an emergency. It isn’t all I do.
I’ve been building and repairing systems since 1995. Whatever brought you here, there’s a good chance I can help with the rest of it too — and you’ll be dealing with the same person either way.
Hacked, but not WordPress?
Joomla, Drupal, Magento, Shopify, PrestaShop, Laravel, Node, IIS and plain HTML — cleaned the same way, priced the same way.
Take a look →Custom builds & AI systems
Plugins, custom applications, website chatbots and automation — built to do exactly what you need, maintained by the person who wrote them.
Take a look →Servers, speed, SEO & accessibility
Migrations, faster load times, technical SEO and accessibility fixes. Measured improvements, with the numbers to show you.
Take a look →Better web hosting
Fast, secure hosting with SSL and backups included at no extra charge. Clear pricing, no long-term contracts, no surprises.
Take a look →Classes & free tools
Rather learn to handle it yourself? I teach this, and I give away the tools I built for my own cleanups.
Take a look →Something else broken?
Half my work is untangling what someone else started, gave up on, or broke. Describe it in plain words and I’ll tell you honestly.
Take a look →Tell me what’s wrong. I’ll tell you what it takes.
No queue, no call centre, no sales pitch — one person who answers, quotes honestly, and does the work.