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.