Two-Factor Authentication on WordPress: The Implementation We Use on Every Client Site
How WitsCode rolls out WordPress two-factor authentication on every client site: which 2FA plugin, TOTP over SMS, role-based enforcement, and lockout recovery.
If you want the short version before the detail, here it is. On every client site we maintain at WitsCode we use the WP 2FA plugin by Melapress, configured for time-based one-time passwords from an authenticator app rather than SMS, enforced for every administrator and editor account and optional for everyone below that. We do not write our own code for this, we do not use SMS codes, and we do not enforce 2FA on subscriber accounts unless the site has a specific reason to. That single sentence is the policy. The rest of this article is why each part of it is the way it is, and what to do on the day the founder drops their phone in a lake.
The reason 2FA matters at all is that the WordPress login form is the most attacked endpoint on the open web. Brute force bots do not care how strong a password is in theory, they care whether they can submit ten thousand guesses against wp-login.php before anything stops them. A password is a single factor, and a single factor that travels in a database dump from some unrelated breach is worth nothing the moment it is reused. Two-factor authentication adds a second proof of identity that the attacker does not have even when they have the password, which turns a credential-stuffing attack from a real risk into a non-event. That is strong enough that we treat 2FA as non-negotiable on any account that can edit content or install plugins.
Which plugin we use and why
There are three credible options for 2FA on WordPress and we have run all of them on real sites. The first is Two-Factor, the plugin maintained by members of the WordPress core team, which is small, free, and the closest thing to an official answer. The second is Wordfence Login Security, which is the standalone login module extracted from the larger Wordfence security suite. The third is WP 2FA by Melapress, which is the one we standardised on.
Two-Factor is genuinely good and we recommend it for anyone running a single personal site. The reason it is not our agency standard is that it has no policy layer. It lets each user turn on 2FA for their own account, but it gives an administrator no way to require it across a role, no grace period, and no central view of who has set it up. For a client site with a founder, two editors, and a freelance contributor who comes and goes, the absence of enforcement means 2FA is on for the people who bothered and off for the people most likely to be the weak link.
Wordfence Login Security solves the enforcement problem but brings the rest of Wordfence's frontend weight into the conversation, and on sites where we have already made a deliberate choice about the security stack we do not want the login module dragging a wider plugin's assumptions along with it. WP 2FA sits in the middle. It is built only for two-factor authentication, it ships role-based enforcement and grace periods as first-class features, it stays out of the frontend, and Melapress maintains it actively. That combination of a narrow scope and a real policy engine is why it is on every site we manage.
TOTP over SMS, every time
The second factor itself should be a time-based one-time password generated by an authenticator app. That means Google Authenticator, Authy, 1Password, Microsoft Authenticator, or any other app that implements the TOTP standard. The user scans a QR code once, the app and the site share a secret, and from then on the app produces a fresh six-digit code every thirty seconds without needing a network connection.
We do not use SMS codes, and the reason is not theoretical. A code sent by text message can be intercepted through SIM swapping, where an attacker convinces a mobile carrier to move a phone number to a SIM they control, and at that point the second factor is delivered straight to the attacker. SIM swap attacks are common enough that the United States National Institute of Standards and Technology has discouraged SMS as an authentication factor for years. TOTP has no such weakness because the secret never travels over a network after the initial setup. The code is computed locally on the device from the shared secret and the current time. There is nothing in transit to intercept.
The other option worth knowing about is a hardware security key using the WebAuthn or FIDO2 standard, the small USB or NFC devices sold under names like YubiKey. These are the strongest factor available and we set them up for clients who ask, particularly for the highest-privilege account on a site that handles payments. For the general case across a client's whole team, TOTP from an app is the right default. It is free, it works on a phone everyone already carries, and it closes the attack we actually see.
Role-based enforcement is the part people skip
Turning on 2FA is easy. Turning it on for the right people, without turning it into a support burden for the wrong people, is the part that separates a policy from a plugin install. WordPress assigns every user a role, and the roles that matter for 2FA are administrator, editor, author, contributor, and subscriber, in descending order of what they can break.
Our standard configuration enforces 2FA as mandatory for administrators and editors. Those are the accounts that can install plugins, edit theme files, change other users, or publish and unpublish content, and a compromised account at either level is a site-level incident. We set authors and contributors to mandatory as well on most sites, because an author account is still a foothold inside wp-admin and an attacker who lands one will use it to probe for a privilege escalation. The line we usually draw is at the subscriber role. On a membership site or a WooCommerce store, subscribers are customers, there can be thousands of them, and forcing every customer through an authenticator setup at checkout will cost more in abandoned carts and support tickets than it saves. So subscribers get 2FA offered, not required, unless the client has a specific reason such as a customer portal exposing sensitive records.
WP 2FA expresses all of this directly. You choose which roles 2FA is required for, and you set a grace period, which is the window a user has after the policy goes live or after their account is created before the requirement actually locks them out of the dashboard. We set the grace period to three days. That is long enough for a real person to find ten minutes to scan a QR code and short enough that a dormant or forgotten account does not sit unprotected for weeks. During the grace period the user sees a prompt on every dashboard load telling them to finish setup, and when the window closes the prompt becomes a wall.
Recovery codes, stored properly
When a user sets up 2FA the plugin generates a set of backup codes, usually ten single-use strings, and this is the safety net for the day the authenticator app is unavailable. Each backup code works exactly once in place of a TOTP code, so a user whose phone is lost or wiped can still log in, then re-enrol a new device and regenerate a fresh set of codes.
The codes are only useful if they are stored somewhere the user can reach when locked out, and somewhere an attacker cannot. A backup code saved as a draft email in the same Gmail account that the WordPress admin email points to is not stored safely, because anyone who compromises that mailbox gets the codes and the password reset link in one place. We tell clients to put backup codes into their password manager as a secure note attached to the WordPress login entry, or onto paper kept somewhere private. The recovery factor must not live in the same basket as the things it is meant to recover. A password manager protected by its own 2FA is the cleanest answer, and most teams already have one.
The lockout recovery path
No matter how good the setup is, someday someone will be locked out. The phone broke, the app was deleted, the backup codes cannot be found, and the founder needs into their own site this afternoon. This is the scenario that makes people nervous about enforcing 2FA at all, so it is worth being precise about the recovery path, because there is always a way back in for anyone with hosting access.
The fastest route is a one-line addition to the theme's functions.php file, edited through the hosting file manager or SFTP rather than the dashboard. WP 2FA, like the other plugins, can be deactivated by force. The cleanest version is to rename the plugin's folder inside wp-content/plugins through the file manager, which WordPress reads as the plugin no longer existing and silently deactivates it. The locked-out user can then log in with just their password, and you rename the folder back and have them re-enrol. If you have WP-CLI access through SSH, which every managed host we use provides, the command is simpler still: wp plugin deactivate wp-2fa removes the requirement in one line, and wp plugin activate wp-2fa restores it afterwards.
The deepest fallback is the database. The 2FA configuration for each user lives in the wp_usermeta table, and deleting the rows whose meta_key values belong to the 2FA plugin for that specific user_id removes their second factor without touching anyone else's. We treat this as the last resort because editing the database by hand is the easiest way to cause a second problem while fixing the first, but it works, and it means no client is ever permanently locked out of a site we manage. The lockout scenario has a known, documented, ten-minute fix for anyone with hosting credentials. It is not a dead end.
Where this fits in a maintained site
Two-factor authentication is one control, not a security strategy. It closes the credential-stuffing and password-reuse attack on the login form, but it sits alongside limiting login attempts, keeping plugins updated, and watching for the unusual login that signals something already went wrong. The plugin choice, the TOTP decision, the role policy, the grace period, and the recovery runbook are each small on their own. Together they are the difference between 2FA that protects a site and 2FA that quietly protects only the two team members who got around to it.
On WitsCode retainers this rollout is part of how we onboard a site rather than a separate project. We install and configure WP 2FA, set the role policy to match the client's actual team, walk every administrator and editor through enrolment on a call, confirm backup codes land in a password manager, and document the lockout recovery path so anyone with hosting access can use it under pressure. Access governance then becomes an ongoing item on the retainer: when a contributor leaves, their account is removed the same week rather than the next year, and when someone new joins, 2FA is part of their first day. If you are running a WordPress site without that structure in place, that managed access governance is exactly the gap a WitsCode maintenance retainer is built to close.
Get weekly field notes.
Practical writing on shipping products, straight to your inbox. No spam.
Need help with this?
WordPress Development
We design and build web apps, MVPs, and SaaS products. Talk to us about what you are working on.
Talk to usWant to discuss wp security & maintenance for your business?
Start a project and we'll talk through where you are, what's working, and the highest-leverage moves for the next 90 days.