All 22 Login Security sections
Password reset requests
The lost-password form sends a real email to a real account every time somebody asks, and anybody can ask. A machine working down a list of usernames fills people's inboxes with reset emails they never asked for, and every one of them goes through your mail service and its allowance.
Settings → Guessing at passwords → Limit password reset emails is on by default, and counts the requests in each hour two ways:
- Emails for one account, three by default: however many addresses ask for it, whether they typed the username or the email address;
- Requests from one address, five by default: whichever names it asks about.
Over either, the request is refused with one sentence, Too many password reset requests. Try again later., and no email is sent.
While the setting is on, an address that is locked out for guessing gets no reset email at all, for as long as the lockout lasts. It is told the same thing the sign-in form told it, with how long is left, for example Too many sign-in attempts from here. Try again in 20 minutes. Signing in is refused to that address for exactly that long whatever password is typed, so a reset email would not get anybody in any sooner. If a real customer is stuck behind a lockout, Let in on their row in the log lets them straight back in, and you can send them a reset from Users → All Users at any time.
What is counted is what gets past everything else on the form:
- a reset email your site makes for an account. An email your site reports it could not send is not counted, so a customer who pressed the button again and again while your mail was broken is not refused once it is mended. A mail plugin that replaces WordPress's own sending and reports nothing back leaves its emails counted;
- a request for a name that is not an account, when WordPress is about to say there is no such account. It sends nothing, but it counts against the name and the address all the same, so the fourth request for a name that is not an account is refused with the same sentence as the fourth for a real one, and the refusal cannot be used to find out which names are accounts.
A request that something else turns away first, such as a CAPTCHA plugin on the same form, uses up nobody's hour. So a machine that cannot get past your CAPTCHA cannot use the limit to stop a real person resetting their password. And because an account's count only fills with emails that went to its owner, somebody who is refused has already been sent those emails, and the newest one still works.
Under the limit, what the form says about a name that is not an account depends on Stop somebody after too many wrong passwords. While it is on, the form answers it as it answers a real account, and sends nothing (see Not telling a machine which half was wrong). While it is off, WordPress's own answer says the name is not an account, and this limit does not hide that.
The limit covers the wp-login.php lost-password form and My Account → Lost password on a WooCommerce shop, where the refusal appears as the shop's own error notice. A request for a name that is not an account is counted the same way on both. So on a connection many people share, such as an office or a mobile network, customers' mistyped names use up that address's requests for the hour too. It also covers any other form that goes through WordPress's own lost-password step. A form that makes its own reset link and sends its own email is not limited.
Trusted addresses and signed-in administrators are never limited. Nor is anybody signed in who sends a reset to somebody else's account they are allowed to edit, such as a shop manager helping a customer from the Users screen; a reset they ask for their own account is counted like anybody's. Jobs your site runs in the background through WP-Cron, such as a plugin sending reset emails to customers it has imported, are not limited either. A background job started another way, such as Action Scheduler's own runner, which calls back into your site through admin-ajax.php, is counted like any request from your server's address. A command run with WP-CLI has no visitor address, so only each account's own count applies to it.
If your site sits behind a proxy the plugin does not recognise (it recognises Cloudflare and a proxy on your own server), every visitor can seem to come from the proxy's one address, and the count for one address is then shared by all of them. Raise Requests from one address if that is your set-up.
The counts work whether or not Record every attempt is on, the same way the sign-in counts do. Each hour starts at the first request. To start them again sooner:
- Let in on a password reset row in the log starts that address's count again, and that account's too;
- Let in on any other row, and
wp login-security unlock <address>, start that address's count again; - Let everybody back in, and
wp login-security unlockon its own, start every count again.
While attempts are being recorded, the log's Password resets tab lists the reset emails that were let through and the requests that were refused, and in a week when any were refused the Dashboard says how many under its numbers. A request for a name that is not an account is only in the log when it is refused. The Refused tab and the Dashboard's other numbers are about signing in, and leave password resets out.
What it does not do: it does not check who is asking, and a request under the limit sends its email as WordPress always has. It does not put a CAPTCHA on the form. Two requests arriving at the same moment can both be let through when only one was left. On a network, each site counts its own requests, and an address locked out on one site is refused a reset there and not on the others.
Still stuck? Ask the developers who wrote it. We aim to reply within one business day.