If you check the access logs on almost any WordPress install with a real domain, you’ll find repeated POST requests to wp-login.php and xmlrpc.php from IPs you don’t recognize. This isn’t targeted — it’s automated scanning that hits every WordPress site it finds, constantly. Most of it is harmless if you’ve closed the obvious doors.
xmlrpc.php is the bigger risk
XML-RPC allows a single request to attempt multiple username/password combinations via the system.multicall method, which makes it far more efficient for brute-forcing than the login form itself. Unless you’re actively using the WordPress mobile app or Jetpack (both rely on it), it’s safe to block entirely:
# In nginx config
location = /xmlrpc.php {
deny all;
}
Rate-limiting the login form
Rather than a full security plugin, a simple failed-attempt lockout does most of the work:
add_action('wp_login_failed', function($username) {
$ip = $_SERVER['REMOTE_ADDR'];
$attempts = (int) get_transient("login_attempts_$ip");
set_transient("login_attempts_$ip", $attempts + 1, 15 * MINUTE_IN_SECONDS);
if ($attempts >= 5) {
wp_die('Too many failed login attempts. Try again in 15 minutes.');
}
});
Renaming wp-login.php isn’t security, but it does cut noise
Moving the login URL doesn’t stop a targeted attacker — anyone who cares can find it. What it does do is remove your site from the pool of low-effort automated scans, which is most of what’s actually hitting a typical site day to day. Worth doing, but don’t mistake it for real protection.
The combination that actually matters: block XML-RPC, rate-limit login attempts, and require strong passwords with two-factor for any account with publish or admin access. Everything else is a smaller improvement on top of that baseline.