Black Friday 40% off yearly and lifetime plans · 18d left Ends in 18d09h23m Claim 40% off
Security38 docs

How to Enable 2FA Rate Limiting in WordPress

Add rate limiting to 2FA verification in Classic Monks. Locks out users after too many failed 2FA attempts to prevent brute force attacks on the second factor.

By Founder & Lead Developer

Last updated

2 minutes

Key takeaways

  • Single toggle with 3 sub-options (max attempts, window, lockout duration)
  • Protects against brute force attacks on 2FA codes
  • Configurable per user or per IP
  • Pairs with [Login Lockdown](security-login-lockdown.md) for defense in depth
  • Returns 403 or shows an error after the threshold

What Is the 2FA Rate Limiting feature?

2FA codes (TOTP or Email OTP) are 6 digits, which means 1 million possible values. An attacker who knows a username can try 1 million codes to find the right one. At 100 attempts per second, that’s ~3 hours to brute force.

The 2FA Rate Limiting feature prevents this by locking out the user (or IP) after a configurable number of failed attempts.

Why You Need It

2FA without rate limiting is a weak 2FA:

  • Brute force feasible: 1M codes is large but not infinite
  • Real-time phishing: Attackers can phish a code in real-time
  • Code reuse: If the same code is captured, the attacker has 30 seconds to use it
  • Knowledge of username: Combined with username enumeration, the attack is targeted

Rate limiting eliminates the brute force vector.

How to Enable 2FA Rate Limiting in WordPress

  1. Step 1

    Navigate to Settings

    Click into the Classic Monks plugin settings in your WordPress dashboard.

  2. Step 2

    Go to the Security Tab

    Click on the Security menu, then click the Two-Factor Auth subtab.

  3. Step 3

    Enable 2FA Rate Limiting

    Scroll to Enable 2FA Rate Limiting and toggle on. Nested options expand.

    Two-factor authentication settings for WordPress.

  4. Step 4

    Configure the Threshold

    Set the Max Attempts. Common values:

    • 3: Aggressive (locks out quickly, may lock out legitimate users who mistype)
    • 5: Default, good balance
    • 10: Permissive (only locks out persistent attackers)

    Enable 2FA rate limiting max attempts

  5. Step 5

    Configure the Window

    Set the Time Window in minutes. The counter resets after this window with no failed attempts. Common values:

    • 5 minutes: Aggressive
    • 15 minutes: Default
    • 30 minutes: Permissive
  6. Step 6

    Configure the Lockout

    Set the Lockout Duration in minutes. How long the user is locked out after exceeding the threshold:

    • 5 minutes: Quick recovery
    • 30 minutes: Default
    • 60 minutes: Stronger protection

    Login attempt settings.

  7. Step 7

    Save Changes

    Click Save Changes.

  8. Step 8

    Test

    Log in with a username and password. Enter wrong 2FA codes 3 times. The 4th attempt should be locked out.

Configuration Options

Option Description Default
Enable 2FA Rate Limiting Master toggle. Off
Max Attempts Number of failed attempts before lockout. 3
Time Window Reset window in minutes. 15
Lockout Duration Lockout duration in minutes. 30

What Gets Affected

  • The 2FA verification: tracks failed attempts
  • The user: locked out after the threshold
  • The login flow: returns 403 or error after lockout
  • The auth cookie: not affected (only 2FA is rate-limited)

What Does NOT Get Affected

  • The password login: not rate-limited (use Login Lockdown for that)
  • The REST API: not affected
  • The TOTP 2FA: still works (just rate-limited)
  • The Email OTP 2FA: still works (just rate-limited)
  • The recovery codes: still work (but also rate-limited)

Advanced Options (Developers)

This feature registers 2 WordPress hooks in 2fa/two-factor-auth.php:

Filters:

  • authenticate calls CM_Two_Factor_Auth::authenticate() (Checks rate limit during 2FA verification)
  • cm_2fa_rate_limit_enabled calls apply_filters() (Customizable filter)
// Hooked in 2fa/two-factor-auth.php
add_filter( 'authenticate', 'CM_Two_Factor_Auth::authenticate' );

The feature modifies WordPress behavior by registering or removing hooks. Disabling it reverses those changes and WordPress returns to its default behavior.

Troubleshooting

5 problems and how to fix each one.

The user is locked out

Cause: The user exceeded the max attempts.
Fix: Wait for the lockout duration. An admin can reset the rate limit for the user from the user profile.

The lockout is too aggressive

Cause: The max attempts is too low.
Fix: Increase the max attempts. Or use the cm_2fa_rate_limit_max_attempts filter to customize per user role.

Legitimate users are being locked out

Cause: The threshold is too low for typical user behavior (e.g., users who retry the code after a clock drift).
Fix: Increase the max attempts or the time window. Educate users to wait for the code to refresh before retrying.

The rate limit is not triggering

Cause: The toggle is off, or a caching plugin is bypassing the 2FA check.
Fix: Verify the toggle is on. The 2FA check happens after the password, so caching should not be an issue unless the entire 2FA flow is cached (which is unusual).

I want to log rate limit hits

Cause: There’s no built-in logging.
Fix: Use the cm_2fa_rate_limit_triggered action to log to your own system. Or use a security plugin that integrates with the WordPress activity log.

Was this doc helpful?

Your answer tells us which docs to fix first.

Still stuck? Ask on the forum or email help@classicmonks.com.
Joy Chetry
Written by the person who built it

Joy Chetry

Founder & Lead Developer, Classic Monks

Joy is the founder of Classic Monks and GoodMonks Solutions, a web development agency that builds WordPress and WooCommerce sites for clients. Classic Monks grew out of the agency's own need to consolidate 20 to 30 separate plugins into one core stack.

Follow this doc on a real site.

Open a private WordPress site with Classic Monks, WooCommerce and Bricks Builder installed, and follow this doc step by step. Free for 24 hours, no card.

280 docs, written by Joy Chetry 15 day refund window