Skip to main content
Blog|
How-to guides

How to secure WordPress login

|
May 15, 2026|17 min read
HOW-TO GUIDESHow to secure WordPress loginHOSTNEYhostney.comMay 15, 2026

Short answer: WordPress login security is layered. Strong unique passwords with two-factor authentication on every admin account, change the default admin username if you still have one, limit failed login attempts at the server level rather than only in WordPress, restrict /wp-admin to known IPs if you can, disable XML-RPC if you do not use it, and set DISALLOW_FILE_EDIT so a compromised admin cannot edit theme or plugin files from the dashboard. Each layer alone is insufficient. Together they make automated attacks economically unviable.

Most WordPress sites are not attacked by humans. They are attacked by bots that try millions of username/password combinations across every WordPress login page they can find. The goal of login security is not to make your site impossible to break into – it is to make the cost of breaking in higher than the value of the result, so the bots move on to easier targets.

Quick reference: the layers#

LayerWhat it doesEffortWhen it stops working
Strong unique passwordsDefeats credential stuffing and dictionary attacksOne-time setup with a password managerNever, if actually unique and 16+ characters
Two-factor authentication (2FA)Stops anyone with only the passwordPer-user enrollment, ~5 min eachWhen the second factor is SMS and the attacker SIM-swaps your phone
Limit login attemptsSlows brute force; bans repeat offendersPlugin install or server configWhen attacker rotates IPs (mitigated by behavioral detection)
Rename wp-login.php Hides the door, breaks naive botsPlugin install, must educate teamWhen attacker scans for the new URL or uses XML-RPC instead
Change admin usernameEliminates half of the credential pair attackers knowOne-time migrationNever
IP allowlist /wp-admin Blocks login attempts at nginx before WordPress sees themServer config, requires static IP or VPNWhen you need to log in from a new location
Disable XML-RPCCloses the secondary brute-force channelOne nginx rule or pluginNever, if you do not use it
DISALLOW_FILE_EDIT Stops a compromised admin from editing PHP files via dashboardOne line in wp-config.php Never
Server-level bot detectionBlocks bots before they reach the login pageProvider responsibility, no work on your sideWhen new bot patterns emerge (continuously updated)

If you are about to write a checklist, the first four are non-negotiable for any production site. The rest depend on whether you have the infrastructure to support them.

Strong, unique passwords on every admin account#

This is the single most effective thing you can do, and it is the step most often skipped because it sounds boring. A 16-character random password generated by a password manager defeats every dictionary attack and every credential stuffing attempt, because the password does not exist anywhere else on the internet.

What “unique” actually means: a password that is not used on any other service, anywhere, ever. Credential stuffing attacks work by buying lists of email/password combinations leaked from other breaches and trying them against WordPress login pages at scale. If your WordPress password is also your Adobe password from the 2013 breach, your site is being tried against that combination tonight whether you know it or not.

A password manager (1Password, Bitwarden, KeePass) is the only practical way to maintain unique passwords across hundreds of services. Generate the password, paste it once into WordPress, and never type it again.

The corollary: any admin account that was created before you started using a password manager has a password that should be assumed compromised. Reset them all. Forcing a one-time reset on every admin user is faster than guessing which ones were created carefully.

Two-factor authentication (2FA)#

2FA defeats the entire class of attack where the attacker has your password but not your second factor. After enabling 2FA, an attacker who phishes your password or buys it on a credential dump still cannot log in. They would need physical possession of your phone or hardware key, which is many orders of magnitude harder.

Enable 2FA on every administrator account. Editor and Author accounts that can publish content should have it too, especially on sites that monetize content or handle payments.

For the plugin choice (TOTP via Google Authenticator / 1Password / Authy, hardware keys via WebAuthn / YubiKey, or backup-code-only setups), best WordPress 2FA plugins compares the active options. The short version: Two Factor (the official Two-Factor plugin from the WordPress core team) covers most needs for free; WP 2FA adds polish and grace periods for organization-wide rollouts; Duo Universal is the right pick if you already use Duo elsewhere.

Avoid SMS as your second factor on high-value accounts. SIM-swapping is a real attack and 2FA via SMS has been broken by it repeatedly. TOTP from an authenticator app is the practical default; a hardware key (WebAuthn / YubiKey) is the strongest option if you can manage one.

Limit failed login attempts#

WordPress out of the box has no rate limit on wp-login.php. A bot can try ten thousand passwords against one admin account in under an hour. Adding a rate limit is the difference between an attack that completes in an hour and one that would take centuries.

There are three layers where the rate limit can live, in increasing order of effectiveness:

Plugin layer (Limit Login Attempts Reloaded, Wordfence, Solid Security): The plugin watches failed logins and bans the offending IP after N attempts in M minutes. This works for most sites and requires no server access. The catch: the plugin only runs after WordPress has fully booted PHP for every login attempt, so a flood of attempts still consumes server resources even when they are getting blocked.

Server layer (fail2ban): fail2ban watches your nginx access log for failed login patterns and adds banning IPs to iptables. Once banned, those IPs cannot even reach nginx. The plugin layer still has work to do because fail2ban needs to see the failed login first, but the second and subsequent attempts from the same IP are blocked at the firewall.

Edge layer (server-level bot detection): The most effective layer is the one that recognizes the bot before it even fingerprints it as a login attempt. Behavioral signals – request rate, header anomalies, lack of JavaScript execution, repeated 404s on plugin probe paths – identify scanners and challenge or ban them at the edge. They never even hit wp-login.php. What happens when bots find your WordPress login page covers what these attacks look like in raw access logs and why behavioral detection scales better than IP-based blocking.

For a detailed look at how brute force attacks actually work and the full range of defenses by layer, brute force attacks on WordPress: how they work and how to stop them breaks down the attack model.

Change the default admin username#

If your site has a user account named admin with administrator privileges, half the credential pair is already public. The attacker only needs to guess the password. Renaming this user (or creating a new one and deleting the old) cuts the search space in half before the first attempt.

WordPress does not let you rename a user through the dashboard. There are three ways to do it:

Create a new admin and delete the old one. Log in as the existing admin, Users > Add New with administrator role and a non-obvious username, log out, log in as the new user, then Users > All Users, hover over the old admin account, and Delete. WordPress asks what to do with the old user’s content; choose “Attribute all content to” and pick the new admin. The old admin’s posts move over and the username is gone.

Direct SQL update. If you have database access:

UPDATE wp_users SET user_login = 'new-admin-username' WHERE user_login = 'admin';

Replace wp_ with your actual table prefix if it differs. The user can log in immediately with the new username.

WP-CLI:

wp user update admin --user_login=new-admin-username

Whichever method you pick, the new username should not be predictable from your site (do not use your domain name, your business name, or your first name as published on the About page). Attackers do read About pages.

Restrict /wp-admin to known IPs#

If you and your team always log in from the same office, home, or VPN, restricting /wp-admin and /wp-login.php to a known IP allowlist eliminates the entire problem at the network level. Attempts from anywhere else get a 403 before WordPress is involved.

This works best for small teams with stable IPs or a VPN. It does not work for sites with many distributed editors, contributors who travel, or developers who work from coffee shops.

nginx allow/deny block in your server config:

location ~ ^/(wp-login\.php|wp-admin/) {
    allow 203.0.113.0/24;   # Office network
    allow 198.51.100.42;    # Home static IP
    allow 192.0.2.10;       # VPN endpoint
    deny all;

    # Then pass through to PHP-FPM as normal
    try_files $uri $uri/ /index.php?$args;
    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php-fpm.sock;
        # ... other fastcgi config
    }
}

The order matters: allow directives are evaluated top to bottom, and the first match wins. deny all at the end catches everything that did not match an explicit allow.

Apache equivalent, in .htaccess inside the WordPress root:

<Files wp-login.php>
    Order Deny,Allow
    Deny from all
    Allow from 203.0.113.0/24
    Allow from 198.51.100.42
    Allow from 192.0.2.10
</Files>

<Directory ~ "wp-admin">
    Order Deny,Allow
    Deny from all
    Allow from 203.0.113.0/24
    Allow from 198.51.100.42
    Allow from 192.0.2.10
</Directory>

What this allowlist blocks: every brute force bot on the internet that does not happen to be on your allow list. What it costs: you lose access to your own site if your IP changes and you forget to update the allowlist. Have a fallback plan (SSH access, hosting panel access, or a colleague’s account on a separate machine) before you tighten this.

What this allowlist does NOT block: XML-RPC. Attackers know /wp-admin is often guarded but xmlrpc.php is often not, so the next section is critical.

Disable or restrict XML-RPC#

XML-RPC is a publishing API WordPress kept around for the Mozilla-Thimble era of remote-editing tools. Almost no one uses it for its original purpose anymore. Attackers use it as a brute-force amplifier – one XML-RPC request can attempt 100+ passwords in a single HTTP call via the system.multicall method, where the equivalent attack against wp-login.php would require 100 separate requests and trip every rate limiter on the way.

If your site does not use XML-RPC (it probably does not), disable it entirely. The full breakdown of how XML-RPC works, what it is used for legitimately, and exactly how to turn it off safely is in WordPress XML-RPC: what it is and how to disable it.

The one-line nginx fix:

location = /xmlrpc.php {
    deny all;
}

Place this above your main location block so it matches first. After reloading nginx, every XML-RPC request returns 403 and the brute-force amplification vector is closed.

If you genuinely need XML-RPC (some Jetpack-dependent setups still do), restrict it to known IPs instead of disabling it, using the same allow / deny pattern as the wp-admin allowlist above.

Rename wp-login.php (with realistic expectations)#

Plugins like WPS Hide Login move your login page to a non-default URL ( /my-custom-login , /secret-door , whatever). Direct visits to /wp-login.php then return 404. This blocks the dumb bots that only know the default URL and provides some “security through obscurity” benefit.

What it actually does:

  • Stops automated bots that hit /wp-login.php by URL and nothing else (which is most of them).
  • Cleans up your access logs – fewer “POST /wp-login.php” lines from bots.
  • Reduces server load from the bot floor.

What it does not do:

  • Hide your login page from determined attackers. A scanner that fetches your homepage and parses the HTML can find the login URL in the body (login pages emit canonical links and references to themselves). Once one bot finds it, the URL is in the lists everyone else uses.
  • Replace 2FA, rate limiting, or strong passwords. It is a noise filter, not a security control.

The decision: install WPS Hide Login if you want quieter access logs and reduced bot load. Do not install it expecting protection – the protection comes from the other layers. The full picture of the login URL, including how WordPress finds it, what to do if a security plugin renamed it and you forgot, and how to recover, is in WordPress login URL: where to find /wp-admin and how to change it.

If you do rename the login URL, document the new URL somewhere your team can find it without depending on the site working. A renamed login URL that nobody remembers is functionally the same as a lockout.

Disable file editing from the dashboard#

WordPress lets administrators edit theme and plugin PHP files directly from Appearance > Theme File Editor and Plugins > Plugin File Editor. This is convenient and almost always a mistake. If an administrator account is compromised, the first thing the attacker does is open one of these editors and write a backdoor into a theme file. They never need to upload a file via FTP or exploit a plugin vulnerability – they just type their malware into your functions.php and click Update.

The fix is one line in wp-config.php :

define( 'DISALLOW_FILE_EDIT', true );

Add it above the /<em> That's all, stop editing! </em>/ comment. After saving, the Theme File Editor and Plugin File Editor menu items disappear and the URLs return 404. Legitimate edits still work via SFTP, SSH, or version control – the only thing that breaks is editing PHP through the browser, which nobody should be doing on a production site anyway.

The full set of wp-config.php security and behavior flags – DISALLOW_FILE_MODS , WP_DEBUG , authentication keys, table prefix – is documented in wp-config.php explained: what every setting does.

DISALLOW_FILE_EDIT does not stop a compromised admin from installing a malicious plugin through the dashboard. For that, the harder flag is DISALLOW_FILE_MODS , which blocks plugin/theme installs and updates entirely. That one is usually too restrictive for normal operations, but it is the right call on locked-down sites where updates are handled exclusively through deployment automation.

User role hygiene#

Every administrator account is a high-value target. The single biggest reduction in attack surface most sites can make is to grant administrator only to people who actually administer the site, and to use Editor, Author, or Contributor for everyone else.

The defaults are correct for the work each role actually does:

  • Administrator – site setup, plugin installs, user management. Two or three people, maximum, even on large teams.
  • Editor – approve and publish content from any user, manage categories, moderate comments. Most editorial leads should be here, not Admin.
  • Author – publish and manage their own posts only.
  • Contributor – write and edit their own posts but cannot publish.

WordPress user roles and user management walks through the capability differences in detail and shows how to enforce a “two admins maximum” policy.

The principle: a hacked Contributor account is a content review problem. A hacked Administrator account is a site rebuild. Give people the smallest role that lets them do their job.

Server-level bot detection#

The single most effective WordPress login defense is one you do not configure – your hosting provider runs it.

Plugin-layer rate limits and 2FA assume the attacker has already reached wp-login.php and is interacting with WordPress. Server-level bot detection (running on the edge web server, not inside WordPress) identifies and stops automated traffic before it ever hits PHP. The detection is behavioral – request rate, missing JavaScript execution, header inconsistencies, repeated probes against known-vulnerable plugin paths – and it scales to billions of requests in ways that a WordPress plugin running per-request inside PHP cannot.

This is one of the reasons Wordfence and server-level security serve different purposes and you need both. Wordfence does excellent application-level analysis once the request is inside WordPress. It cannot prevent a million bot requests from consuming PHP workers because it runs as a plugin, after PHP has spun up. Edge detection runs in nginx or Lua and discards bot requests in microseconds.

When evaluating hosting from this angle, the question to ask is: “does the edge layer block automated traffic to /wp-login.php before PHP runs?” If yes, the volume of password attempts your site sees drops by 90+% before any of the layers above this matter.

How long does each layer take to set up#

LayerSetup timeOngoing time
Password manager rollout30 min per admin (one-time)None
2FA on all admin accounts5 min per admin (one-time)~5 sec per login
Rename admin username10 minNone
Install login-limit plugin10 minOccasional review of banned IPs
nginx IP allowlist30 min + DNS coordinationUpdate on IP change (rare with VPN)
Disable XML-RPC5 minNone
DISALLOW_FILE_EDIT 1 minNone
Rename wp-login.php10 minDocument new URL for team
Audit and downgrade admin accounts1 hourQuarterly review

The first eight items combined are less than three hours of work for a typical site. The hardest part is making the team actually use the password manager and 2FA codes; the technical setup is the easy bit.

Common mistakes when securing WordPress login#

Treating any single layer as sufficient. “I have 2FA, I don’t need rate limiting” is the most common bad take. 2FA stops password-knowing attackers from logging in; it does not stop bot floods from hammering your server. Rate limiting stops the floods but does not protect against a single attacker who has your password and second-factor code. Layers exist because each one fails differently.

Renaming wp-login.php and stopping there. Hiding the login URL is a noise filter, not a defense. Sites that “secure” their login by renaming the URL and skipping 2FA are exactly as vulnerable as sites with the default URL and no other defenses.

Using SMS for 2FA on high-value accounts. SIM-swapping attacks against high-profile WordPress site owners are routine. Use an authenticator app (TOTP) at minimum; use a hardware key for sites with significant attack value.

Allowlisting /wp-admin but forgetting /xmlrpc.php . Locking down the front door while leaving the side door open. XML-RPC is the path most attackers will pivot to.

Keeping admin as a real username. Even if the password is strong, you are giving the attacker half of every credential pair for free.

Forgetting to enforce strong passwords on Editor and Author accounts. A compromised Author account can publish malicious content with the site’s authority and SEO weight. Their passwords need to be as strong as admin passwords are.

Not testing the IP allowlist before reloading nginx. Always have a way back in – SSH, hosting panel, or a colleague who can revert the change – before you tighten access rules on a site you log in to remotely.

Skipping the audit of existing user accounts. Every “security audit” that does not start with wp user list --role=administrator is incomplete. Old accounts from former employees, contractors, or one-time agency engagements are common attack surface. If your site was hacked recently, my WordPress site was hacked: what to do right now covers the full backdoor-account hunt.

Disabling everything that says “API” without checking. XML-RPC should usually go. The REST API ( /wp-json/ ) is different – WordPress core uses it for the block editor, Gutenberg, and most modern plugins. Disabling the REST API breaks things. Disable XML-RPC, restrict REST endpoints if you want to, but do not flip a “disable APIs” switch as a single mass action.

Login security on Hostney#

On Hostney, several login security layers are infrastructure rather than per-site configuration:

  • Edge bot detection (the Lua layer running in OpenResty) identifies and challenges automated traffic to /wp-login.php and /xmlrpc.php before PHP runs. The bot is rate-limited, challenged with proof-of-work, or banned outright based on behavioral signals – none of which depend on a plugin being installed or configured per-site
  • ModSecurity with the OWASP Core Rule Set blocks the common credential-stuffing patterns at the WAF layer
  • TLS-only login – sessions over HTTPS only, no fallback – is enforced at the web server
  • One-click SSO from the control panel lets you and any delegate-access user reach /wp-admin without ever typing a password into wp-login.php . The mechanism uses a one-time SHA-256 hashed token with a 60-second TTL, so the credential pair is never reused or stored in a browser. On installs where you set the security_sso_only flag, direct wp-login.php access is disabled entirely – WordPress login can only happen through the panel

The per-site layers – password hygiene, 2FA enrollment, admin-username choice, DISALLOW_FILE_EDIT , role assignments – are still your responsibility. The infrastructure handles the part that scales (bot floods, edge filtering) and leaves the part that requires judgment (which users get which role) to the team that knows the site. Direct WordPress login attempts ( /wp-login.php and /xmlrpc.php ) are filtered at the edge but are not currently surfaced as a per-site activity feed – the panel’s login history covers control-panel, SSH, and SFTP sessions, not WordPress login attempts directly. For per-site WordPress login visibility, a security plugin (Wordfence’s Live Traffic, Solid Security’s logs) is still the practical option today.

For the broader picture of how login security fits into a complete WordPress hardening setup, is WordPress secure and how to harden it walks through the three-layer model. For the security-plugin layer specifically, best WordPress security plugins (free and paid) compares Wordfence, Sucuri, Solid Security, AIOS, MalCare, and Jetpack Protect. If you are running into login problems unrelated to security (refresh loops, redirect loops, cookie issues), that is covered separately in WordPress login page refreshing and redirecting, and recovery from a full lockout is covered in locked out of WordPress admin: how to get back in.

Quick checklist#

  • [ ] Every admin password is 16+ characters, unique, and lives in a password manager
  • [ ] 2FA is enabled on every administrator account (TOTP minimum, hardware key preferred)
  • [ ] The admin username no longer exists; admin usernames are not predictable from your site
  • [ ] A login-limit plugin or fail2ban rule limits failed login attempts per IP
  • [ ] /wp-admin and /wp-login.php are IP-allowlisted (where team distribution allows it)
  • [ ] XML-RPC is disabled or restricted to known IPs
  • [ ] DISALLOW_FILE_EDIT is set in wp-config.php
  • [ ] No user accounts remain from former contractors, agencies, or one-time engagements
  • [ ] Only the people who administer the site have the Administrator role
  • [ ] Login activity is visible (control panel dashboard, security plugin, or access-log review schedule)

The first four cover 90% of the attack surface. The rest are how you take the remaining 10% to “not economically worth attacking.”