Bots are hammering your WordPress login page right now — thousands of guesses a day, hoping one lucky try opens the door. Learning how to limit login attempts in WordPress without a plugin is the fastest way to slam that door shut, before a bot finds the one password that works.
WordPress Does NOT Limit Login Attempts by Default
WordPress core has no built-in failed-login lockout — no cap on attempts, no delay after wrong passwords, no alert after hundreds of tries. Brute force is a numbers game: given unlimited attempts, a bot can test thousands of common passwords against your admin username.
Key takeaway: without a limit, your site allows unlimited login attempts — and bots know it. Limiting attempts pairs well with How to Protect WordPress From Brute Force Attacks and How to Secure a WordPress Site Without a Plugin.
Recommended Settings: How Many Attempts Should You Allow?
- Allowed attempts: 3 to 5 failed logins before a lockout. Three is stricter.
- First lockout: 20 to 30 minutes — long enough to stop bots, short enough for real users.
- Escalating lockouts: longer next time — 60 minutes, then 24 hours.
- Lockout scope: lock by IP address, not by username alone — username locks let attackers lock you out.
- Reset on success: a successful login clears the counter.
Key takeaway: 5 attempts, a 30-minute first lockout, then escalating lockouts is the sweet spot.
Method 1: Safe Lockout Code (a Site-Specific Plugin — NOT functions.php)
This is the most complete method — and the one stale tutorials get wrong: they tell you to paste code into functions.php. Do not: it gets overwritten on every theme update, silently removing your protection, and a typo can take down your site.
The safe approach is a small site-specific plugin: one PHP file in wp-content/plugins/, activated like any plugin. It survives theme updates and deactivates instantly.
How the code works
It uses three hooks. wp_login_failed counts failed logins per IP in a transient (a temporary, auto-expiring database value). authenticate checks the counter before WordPress verifies the password and blocks locked-out IPs. wp_login clears the counter on success — and the lockout message shows the time remaining.
The complete code
Create limit-login-attempts-custom.php in wp-content/plugins/limit-login-attempts-custom/ and paste this:
<?php
/**
* Plugin Name: Limit Login Attempts (Custom)
* Description: Limits failed login attempts by IP with escalating lockouts.
* Version: 1.0
* Author: TechCoff
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
define( 'LLA_MAX_ATTEMPTS', 5 );
define( 'LLA_LOCKOUT_MINUTES', 30 );
define( 'LLA_ESCALATED_MINUTES', 1440 );
define( 'LLA_WINDOW_HOURS', 12 );
function lla_get_ip() {
$ip = $_SERVER['REMOTE_ADDR'];
if ( ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
$f = explode( ',', sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) );
$ip = trim( $f[0] );
}
return sanitize_text_field( $ip );
}
function lla_attempts_key( $ip ) { return 'lla_attempts_' . md5( $ip ); }
function lla_lockout_key( $ip ) { return 'lla_lockout_' . md5( $ip ); }
add_action( 'wp_login_failed', function () {
$ip = lla_get_ip();
$key = lla_attempts_key( $ip );
$attempts = (int) get_transient( $key ) + 1;
set_transient( $key, $attempts, LLA_WINDOW_HOURS * HOUR_IN_SECONDS );
if ( $attempts >= LLA_MAX_ATTEMPTS ) {
$offenses = (int) get_option( 'lla_offenses_' . md5( $ip ), 0 ) + 1;
update_option( 'lla_offenses_' . md5( $ip ), $offenses );
$minutes = ( $offenses > 1 ) ? LLA_ESCALATED_MINUTES : LLA_LOCKOUT_MINUTES;
set_transient( lla_lockout_key( $ip ), time() + ( $minutes * MINUTE_IN_SECONDS ), $minutes * MINUTE_IN_SECONDS );
delete_transient( $key );
}
} );
add_filter( 'authenticate', function ( $user, $username ) {
if ( empty( $username ) ) {
return $user;
}
$until = get_transient( lla_lockout_key( lla_get_ip() ) );
if ( $until && $until > time() ) {
$minutes = (int) ceil( ( $until - time() ) / MINUTE_IN_SECONDS );
return new WP_Error( 'too_many_attempts', sprintf( 'Too many failed login attempts. Please try again in %d minute(s).', $minutes ) );
}
return $user;
}, 30, 2 );
add_action( 'wp_login', function () {
delete_transient( lla_attempts_key( lla_get_ip() ) );
} );
Activate it under Plugins, then test it with five wrong passwords.
Key takeaway: a site-specific plugin gives plugin-grade protection without installing a plugin.
Take a small store hit by a bot trying 2,000 passwords an hour: five guesses, then a 30-minute lockout, then 24 hours.
Method 2: .htaccess IP Allowlist for wp-login.php
If only you log in, from one or two known IPs, an .htaccess allowlist is the strongest option: it blocks everyone except your IP from reaching the login page. Add this above # BEGIN WordPress in your root .htaccess (use your own IP):
<Files wp-login.php>
Order Deny,Allow
Deny from all
Allow from 123.45.67.89
</Files>
The catch: it only works if your IP rarely changes — find yours by searching “what is my IP”. Skip it if several people log in from different places.
Method 3: Free Cloudflare Rate Limiting for the Login Page
If your site already sits behind Cloudflare’s free plan, you can limit logins before traffic reaches it. In Cloudflare, go to Security → WAF → Rate limiting rules, create a rule named “Limit wp-login attempts” matching URI paths containing wp-login.php: 5 requests per 1 minute per IP, Block for 30 minutes. Free on Cloudflare’s free plan — see Cloudflare’s rate limiting rules documentation.
Blocked bots never touch your server — if Cloudflare is proxying your traffic.
Method 4: When a Plugin Is the Right Call
Sometimes code is not the right answer — if you manage client sites or want email alerts, a plugin is the pragmatic choice.
| Method | Skill needed | Cost | Best for |
|---|---|---|---|
| Site-specific plugin code (Method 1) | Basic — one file | Free | FTP/File Manager users |
| .htaccess IP allowlist (Method 2) | Basic — one file | Free | Single admin, static IP |
| Cloudflare rate limiting (Method 3) | Intermediate — dashboard | Free | Sites on Cloudflare |
| Limit Login Attempts Reloaded | None | Free | Settings + alerts |
| Wordfence Login Security | None | Free | Wordfence users |
| Login LockDown | None | Free | Simple lockouts |
Limit Login Attempts Reloaded is the most popular free option on WordPress.org — lockouts, IP lists, and email alerts from a settings page. Wordfence Login Security adds login limits plus 2FA in one free plugin. Login LockDown is the lightest: simple limits, almost no setup.
Key takeaway: the best method is the one you will keep enabled.
What to Do If YOU Get Locked Out of WordPress
Every lockout needs a recovery path. Easiest first:
- Wait it out. The first lockout is only 30 minutes.
- Rename the plugin folder. In File Manager, rename
wp-content/plugins/limit-login-attempts-customto...-off. WordPress deactivates it; log in, then rename it back. - Clear the transients via phpMyAdmin. In phpMyAdmin run:
DELETE FROM wp_options WHERE option_name LIKE '_transient_lla_%';(adjust thewp_prefix). Back up first. - For .htaccess lockouts, delete the allowlist block or add your new IP, via File Manager.
- For Cloudflare lockouts, disable the rate limiting rule.
Key takeaway: you can never permanently lock yourself out — renaming the plugin folder always gets you back in.
Lockout + 2FA + Hidden Login URL = Layered Defense
Limiting attempts is one layer, not the whole wall. Stack three: login limits cap guesses; two-factor authentication makes a guessed password useless — see How to Add Two-Factor Authentication to WordPress; a hidden login URL moves wp-login.php — see How to Change the WordPress Login URL.
Together, they stop most brute force attacks on small sites. Prefer a professional? See services or contact — a one-time setup beats cleaning up a hack.
FAQ
Does WordPress limit login attempts by default?
No — by default, bots get unlimited login attempts. You need custom code, server rules, Cloudflare rate limiting, or a plugin — developers build this with the wp_login_failed hook.
How many login attempts should I allow in WordPress?
Allow 3 to 5 failed attempts. Five suits users who mistype passwords; three is stricter for high-risk sites. Pair it with a 20–30 minute first lockout, longer for repeat offenders.
What happens if I get locked out of WordPress?
You see a lockout message with the time remaining and cannot log in until it expires — usually 30 minutes. If you cannot wait, rename the plugin folder, clear the transients in phpMyAdmin, or disable the Cloudflare rule.
Is limiting login attempts enough to stop brute force attacks?
It stops the guessing, but it is not complete protection alone. Combine login limits with strong unique passwords, two-factor authentication, and a hidden login URL.
The Takeaway: Five Guesses, Then the Door Locks
Bots will keep knocking — the only question is how many free guesses you give them. Set the limit today: five attempts, a 30-minute lockout, and a recovery path tested before you need it. Then add 2FA, hide the login URL, and stop giving bots unlimited chances to guess their way in.