Why My 2FA Code Is Not Working: A Troubleshooting Guide
Security Tools

Why My 2FA Code Is Not Working: A Troubleshooting Guide

You open your authenticator app, read off the six digits, type them in, and the site says the code is invalid. You try again — still rejected. Few security errors are as frustrating, because everything looks right: the app is showing a code, the code is fresh, and you are certain you typed it correctly. The good news is that almost every "2FA code not working" case comes down to a small handful of causes, and they can be ranked by how often they actually happen. This guide walks through them in order of likelihood, explains why each one breaks the code, and shows how to fix it. If you want to see the mechanism directly, our TOTP Generator lets you watch codes change against a live clock so you can reproduce and diagnose the failure yourself.

First, How a TOTP Code Is Actually Computed

Time-based one-time passwords are defined by RFC 6238. The algorithm is deterministic: it takes a shared secret (fixed at enrolment), the current Unix time, and a small set of parameters, and produces a code. The critical step is that the current time is divided into fixed windows — by default 30 seconds each — and the window number becomes a counter. That counter is fed through HMAC with the shared secret, and the result is truncated to the final digits you see. Both your app and the server run the exact same computation. If both agree on the secret, the parameters, and the current time window, they produce the same code. If any one of those three disagrees, the codes differ and the server rejects yours. Nearly every failure is one of those three going out of alignment. Our pillar explainer, how TOTP authentication works, covers the full derivation if you want the underlying detail.

Cause #1 (By Far the Most Common): Your Device Clock Is Out of Sync

This is the single largest source of rejected codes, so start here before anything else. Because the counter comes from your device's own wall-clock time, a phone whose clock is even a couple of minutes off computes the code for the wrong 30-second window. The math runs perfectly; it just runs on the wrong input. If your clock is 90 seconds fast, your app is effectively showing you a code from three windows in the future, and the server — which trusts its own accurate time — sees a code that does not match the window it expects, so it rejects it.

The subtle part is that the clock error does not have to be large. Servers usually accept a small drift window of one or two steps on either side (about ±30 to ±60 seconds) to tolerate minor skew and transmission delay. That tolerance is exactly why a phone that is two or three minutes out fails every single time while a phone that is only twenty seconds out still works. It also explains why the failure can feel random: right after a manual clock change or a time-zone-related glitch, you cross the tolerance boundary and codes silently start being rejected.

The fix is to stop setting the time by hand and let the network set it:

  • Android: Settings → System → Date & time → enable Set time automatically (uses the network time). Turn off any manual override.
  • iPhone: Settings → General → Date & Time → enable Set Automatically. If it is already on, toggle it off and back on to force a re-sync.
  • Windows: Settings → Time & language → Date & time → turn on Set time automatically, then click Sync now.
  • macOS: System Settings → General → Date & Time → enable Set time and date automatically.

Automatic network time keeps your device continuously aligned to reference clocks, which is far more accurate than any human can set a watch. After enabling it, wait a few seconds for the sync to land, then read a fresh code.

Some authenticator apps also carry their own defense against this. Google Authenticator, for example, has a "Time correction for codes" option (under Settings) that queries a time server, measures the offset between your device clock and real time, and applies that correction internally when generating codes — without changing your system clock. If you cannot fix the device clock immediately (a work-managed phone, for instance), running that correction gets your codes accepted again. If your app lacks such a setting, fixing the OS clock is the reliable path.

Cause #2: The Service Uses Non-Default Parameters (Algorithm, Digits, or Period)

RFC 6238 has defaults — HMAC-SHA-1, 6 digits, a 30-second period — and the vast majority of services use them. But the standard explicitly permits other choices, and some services pick them: SHA-256 or SHA-512 instead of SHA-1, 8 digits instead of 6, or a 60-second period instead of 30. When you enrolled, those parameters were meant to be carried in the setup QR code (the otpauth:// URI has algorithm, digits, and period fields). If your authenticator ignored one of them — or if you typed the secret in manually and the app fell back to its defaults — your app computes SHA-1/6-digit codes while the server expects SHA-256/8-digit codes. Every code will be wrong, and it will be wrong consistently, which is the tell that distinguishes this from a clock problem.

How to recognize it: if the server is asking for an 8-digit code but your app only ever shows 6 digits, the digit count is mismatched — that one is obvious. The algorithm mismatch is invisible from the outside (both produce a code of the right length) but fails identically every time regardless of your clock. If you suspect this, re-enrol from the original QR code with an app that honors the parameters, or verify the values directly. Our TOTP Generator exposes the advanced parameters — algorithm, digit count, and period — so you can set them to match the service and confirm which combination produces the code the server accepts. Our companion article on when services use SHA-256 or 8-digit TOTP lists the situations where this actually comes up and how to detect it.

Why My 2FA Code Is Not Working: A Troubleshooting Guide

Cause #3: The Secret Was Mistyped or Wrongly Transcribed at Enrolment

If you set up the account by typing the secret key by hand instead of scanning the QR code, a single wrong character means your app and the server are seeded with different secrets — and different secrets can never produce matching codes. TOTP secrets are encoded in base32, which uses the letters A–Z and the digits 2–7. That alphabet deliberately omits the visually ambiguous characters, but transcription errors still creep in: a 0 written where an O belongs, a 1 for an I or l, a 8 for a B, or a dropped or duplicated character. Base32 is also case-insensitive and often grouped in blocks of four with spaces — the spaces and case are cosmetic, but the letters and digits must be exactly right.

The signature of a bad secret is the same as a parameter mismatch: every code fails, immediately, no matter how good your clock is. If you cannot rule out a typo, the cleanest fix is to remove the account from your authenticator and re-enrol by scanning the QR code, which transfers the secret without any manual typing. When only a text secret is offered, paste it rather than retyping it, and double-check it against base32's A–Z/2–7 alphabet before saving.

Cause #4: You Reused a Code, or Entered It a Moment Too Late

A TOTP code is valid only for its own time window. Two related timing mistakes cause a code that was correct to be rejected:

  • Entering it just after rollover. If a code has only a few seconds left when you start typing, it can expire between reading it and submitting it. The server has already moved to the next window and the code you sent belongs to the previous one. Many servers accept the immediately previous window to soften this, but that grace is not guaranteed. The habit that avoids it: when the countdown ring is nearly empty, wait for the code to refresh and use the new one rather than racing the old one.
  • Reusing a code the server has already consumed. Good implementations reject a code that has already been used successfully within its window, precisely so an intercepted code cannot be replayed. If you submitted a code, got interrupted, and submit the same code again, it can be refused as already-spent even though it looks current. Wait for a fresh code and submit that.

Cause #5: You Typed an Old Screenshot or Stale Code

Codes captured out of their moment are dead on arrival. If you screenshotted a code to paste later, or you are reading from a notification that has been sitting on screen, the underlying window has long since passed even though the digits are still visible. The number on screen is a snapshot of a window that no longer exists. Always generate — and immediately use — a live code from the app itself; never store a TOTP code for later.

Cause #6: The Wrong Account Entry Is Selected in the App

If you use one authenticator for many services, it is easy to read the code from the wrong row — two work accounts, or a personal and a work login for the same provider, sitting next to each other. The code is perfectly valid; it just belongs to a different account, so the server you are logging into rejects it. Check that the label and the account/email on the entry match the exact account you are signing in to, then read the code from that specific row.

A Fast Diagnostic Order

When a code is rejected, work through the causes in this order, because it moves from most-likely to least-likely and each step rules a class of problems in or out:

  • Is only sometimes failing, or failing near the end of the countdown? Suspect timing (Cause #4/#5) — wait for a fresh code.
  • Failing every time, immediately, on a fresh code? The clock, the parameters, or the secret is wrong. First enable automatic network time (Cause #1) and try again — this fixes the largest share of cases.
  • Still failing every time with a correct clock? Check digits and algorithm (Cause #2), then re-enrol by QR to rule out a mistyped secret (Cause #3).
  • Multiple accounts in the app? Confirm you are reading the right row (Cause #6).

Understanding why each of these breaks the code — rather than just following steps — makes the fix obvious next time. Because TOTP is fully deterministic, a rejected code always means one of the three inputs (secret, parameters, or time window) is misaligned, and this ordering finds which one fastest. To see the moving part with your own eyes, open the TOTP Generator: it shows the countdown, warns when your browser clock looks skewed, and lets you dial in the advanced parameters so you can reproduce exactly the combination your service expects.

← Back to Blog