AuthHound

Login incorrect (...): [user] (from client ...)

FreeRADIUS 'Login incorrect' — find the real reason in radiusd -X

The log line:

(8) Login incorrect (mschap: ERROR: MS-CHAP2-Response is incorrect): [alice] (from client office-ap port 0 via TLS tunnel)

What it actually means: almost nothing by itself — and that’s the point of this page. Login incorrect is FreeRADIUS’s summary line, printed for every deliberate reject regardless of cause. Treating it as the diagnosis is the most common dead end in FreeRADIUS troubleshooting. The actual reason is always earlier in the debug output; here’s how to walk to it.

1. Read the parentheses first

Since FreeRADIUS 3, the summary line includes the failing module’s own message in parentheses — (mschap: ERROR: ...), (pap: ...), (eap_peap: ...), (rlm_ldap: ...). That names the module and often the whole answer. Frequent parentheticals and where they lead:

Parenthetical containsReal problemDeep dive
mschap: ... MS-CHAP2-Response is incorrectwrong password / hash format / AD account stateMSCHAPv2 page
No "known good" passwordbackend never supplied a passwordknown-good password page
eap: ... EAP sub-module failedlook further up for the TLS alertunknown CA, expired cert
rlm_ldap / sql errorsbackend lookup or bind failureLDAP bind page

2. Walk up to the last authenticate section

Find the request number — the (8) prefix — and read only lines with that prefix (in a busy debug, interleaved requests are the great confuser; grep '^(8)' is your friend). Locate the authenticate { block and read which module returned reject or fail:

(8)     [mschap] = reject
(8)   } # authenticate = reject

Everything above that module’s own ERROR lines is context; the first ERROR from that module is the diagnosis.

3. If no module errored — it’s your policy

Sometimes nothing “failed”: an unlang policy deliberately rejected (a group check, a NAS filter, a time restriction). Search the request’s lines for Post-Auth-Type REJECT and for reject inside policy / authorize sections — the surrounding lines name the condition that fired.

The habit that makes this fast

Never debug from /var/log/radius/radius.log — its one-line summaries are exactly the trap this page describes. Reproduce the failure once under radiusd -X (or raddebug on a running server) and you get every decision the server made, in order. Then the reject is never mysterious: it’s the last module that said no, for the reason printed right above it.

Reproduce it on demand instead of waiting for the next complaint: the open-source authhound-probe triggers a real authentication from your desk with a known-good account — if that fails too, it was never the user’s password.

export AUTHHOUND_RADIUS_SECRET='shared-secret'   # not in argv or shell history
authhound-probe radius test --server radius.corp.com --peap alice

Quickstart: install, register, first test

Have the full log open? Paste it here

The analyzer detects this exact failure and 18 others, and ranks the likely causes for your specific output. It runs entirely in your browser — nothing is uploaded.

This failure is usually invisible until users complain. AuthHound is building continuous monitoring that catches it first — early access:

No spam, no sharing — one email when it's ready, and you can reply to be removed anytime.