Error 18456 is the most common login failure in SQL Server, and the message you get is deliberately vague:
That is all the client is told, on purpose. If SQL Server explained exactly why a login failed, it would be handing an attacker a checklist. The real reason is written to the SQL Server error log as a state number, and that number is the whole game.

I have spent more time than I would like reading these states at awkward hours, so here is the version I wish I had found first.
Get the State Number First
Everything below depends on this. Without the state you are guessing. The state numbers are documented on Microsoft Learn; the table below is that list with what each one turns out to be in practice.
-- The two halves of a login failure are on SEPARATE lines in the log,
-- and no single filter returns both: the Error line does not contain 'Login failed',
-- and the Reason line does not contain '18456'. Read twice and union.
DECLARE @log TABLE (LogDate datetime, ProcessInfo nvarchar(64), Txt nvarchar(max));
INSERT INTO @log EXEC xp_readerrorlog 0, 1, N'18456'; -- gives you the State
INSERT INTO @log EXEC xp_readerrorlog 0, 1, N'Login failed'; -- gives you the reason and the client
SELECT TOP (20) LogDate, Txt
FROM @log
ORDER BY LogDate DESC;

You are looking for a line like:
Error: 18456, Severity: 14, State: 8.
Login failed for user 'sa'. Reason: Password did not match that for the login provided. [CLIENT: 10.0.0.42]
That State: 8 is the answer. The client normally receives only the generic State 1: the real reason is deliberately kept server-side so failed logins cannot be used to probe accounts, which is why the error log, not the client message, is where diagnosis starts.
If you cannot get into the instance at all, the log is still readable on disk, usually at ...\MSSQL\Log\ERRORLOG, and any text editor will open it.
What Each State Actually Means
| State | Meaning | What it usually is in practice |
|---|---|---|
| 1 | Error information is not available | You do not have permission to see the real state. The server error log has it; ask whoever can read it, or read it yourself if you can. |
| 2 | User ID not valid | Login does not exist. Often a typo, or a login that was dropped |
| 5 | Login not found | Same as 2 in practice. Check spelling and the domain part |
| 6 | Windows login used with SQL authentication | The connection string says SQL auth but the login is a Windows account |
| 7 | Login disabled and password wrong | 2 problems at once. Fix the password after enabling |
| 8 | Password did not match | Genuinely the wrong password. The most common of all |
| 9 | Password not valid | Documented as its own state; in practice treat it exactly like 8 |
| 11 | Valid login, but server access denied | Windows login is valid, has no permission to connect. Often a missing group membership, or access that only comes through the local Administrators group and the client was not started as administrator |
| 12 | Valid login, server access denied | As 11, usually a login that exists but was denied CONNECT SQL |
| 18 | Password must be changed | MUST_CHANGE is set on the login |
| 38 | Database not found | The login is fine. The database in the connection string does not exist or is offline |
| 46 | Database requested not found | Documented alongside 38, same practical meaning: check the database, not the credentials |
| 40 | Cannot open the default database | The login’s default database is offline, dropped, or in single user mode |
| 58 | SQL login used when only Windows auth is enabled | The instance is in Windows Authentication mode. Microsoft also lists a SID mismatch under this state, which is the rarer cause |
| 62 | Contained database SID mismatch | A Windows account reaching a contained database whose user SID no longer matches, usually after a restore between servers |
| 102-111, 132-133 | Azure AD / Entra failure | Cloud authentication problems on Azure SQL, not passwords |
| 122-124 | Empty user name or password | The connection string lost its credentials, common after config templating goes wrong |
| 126 | Database requested does not exist | The Azure-era sibling of 38 |
States 8, 38 and 40 cover the large majority of real incidents. If you are in a hurry, check those 3 first.
The Fixes, By State
Wrong Password
Confirm the login exists and is not locked out before assuming the password is simply wrong:
SELECT name,
is_disabled,
LOGINPROPERTY(name, 'IsLocked') AS is_locked,
LOGINPROPERTY(name, 'IsMustChange') AS must_change,
LOGINPROPERTY(name, 'BadPasswordCount') AS bad_password_count,
LOGINPROPERTY(name, 'PasswordLastSetTime') AS password_last_set
FROM sys.sql_logins
WHERE name = N'your_login';
A non-zero bad_password_count with a recent PasswordLastSetTime usually means an application is still holding an old password and retrying, which is also how accounts get locked out. Find the application before resetting the password, or you will do this again tomorrow.
In a corporate environment the Windows sibling of this error, 18452, is the one I see more than almost any other, and when I do it is usually the same story as State 8: the account is locked out, or the password changed and the client is still holding the old one.
The Database Is the Problem, Not the Login
This is the state that fools people, because the login is perfectly fine. State 38, and 46 which Microsoft lists alongside it, means the database the connection string asked for: the reason line reads Failed to open the explicitly specified database 'YourDb'. State 40 means the login’s default database instead, and its reason line reads Failed to open the database 'YourDb' specified in the login properties. Check the database either way:
-- Is the database actually there and online?
SELECT name, state_desc, user_access_desc, is_read_only
FROM sys.databases
WHERE name = N'your_database';
If state_desc is anything other than ONLINE, that is your answer. RECOVERING, SUSPECT and OFFLINE all produce a login failure that looks like a permissions problem. If the database is not there at all and this is State 38, the fix is on the client: the connection string’s Initial Catalog names a database that was renamed, dropped or never existed on this instance.
For State 40 the login’s default database is the problem, and the login can be fixed without touching the database:
ALTER LOGIN [your_login] WITH DEFAULT_DATABASE = [master];
Valid Login, No Access
Almost always a Windows login whose access came through a group that has changed. Check what the server actually thinks the login can do:
SELECT sp.name,
sp.type_desc,
sp.is_disabled,
spm.permission_name,
spm.state_desc
FROM sys.server_principals sp
LEFT JOIN sys.server_permissions spm
ON spm.grantee_principal_id = sp.principal_id
AND spm.permission_name = 'CONNECT SQL'
WHERE sp.name = N'DOMAIN\your_login';
No CONNECT SQL grant, or a DENY, is the cause:
GRANT CONNECT SQL TO [DOMAIN\your_login];
If the grant is there and State 11 keeps coming, read the reason line. Token-based server access validation failed with an infrastructure error usually means the user’s only route in is the local Administrators group, and Windows does not present that membership unless the client is elevated. Start SSMS with Run as administrator to get in, then add the Windows user as a login in its own right so it stops depending on the group.
SQL Login on a Windows-Auth-Only Instance
-- 1 = Windows Authentication only, 0 = Mixed Mode
SELECT SERVERPROPERTY('IsIntegratedSecurityOnly') AS windows_auth_only;
If this returns 1 and you need SQL logins, the instance must be switched to Mixed Mode, which requires a service restart. That is a change-window job, not a quick fix.
Windows Login, SQL Auth Connection String
Nothing is wrong with the server. The connection string is using a username and password for an account that is a Windows login. Switch it to integrated security.
The One That Is Not a Login Problem at All
If the error log shows no 18456 entry at the time of the failure, the connection never reached the authentication stage. That is a network, TLS or protocol problem wearing a login error’s clothing, and you should be looking at the pre-login handshake instead.
Stopping It Recurring
- Lockouts that keep coming back are almost always a service, scheduled task or connection pool holding a stale password. Find it before resetting.
- State 38 in bulk usually means an application is connecting to a database that was renamed or dropped, and nobody updated the connection string.
- Grant server access through groups, not individual logins. State 11 and 12 mostly happen when a person’s group membership changes and their individual grant was never there to begin with.
Frequently Asked Questions
Why does the client only ever show State 1?
The password is definitely right, so why State 8?
BadPasswordCount with a recent password change usually means an application is still retrying an old password, which is also what locks the account.There is no 18456 in the error log at all. What now?
Lots of 18456s and I do not know which machine they are coming from.
EXEC xp_readerrorlog 0, 1, N'Login failed'; and each entry ends with the source, like [CLIENT: 10.0.0.25], alongside the login name and the reason. That turns “something is hammering us” into an address you can chase. Watch for a regular interval in the timestamps: a failure landing every 15 minutes on the dot is a scheduled job or a monitoring agent, not a person mistyping a password, and the reason text usually names the database it could not open.How do I find the state on Azure SQL Database?
xp_readerrorlog is not there to call. Failed logins, with their reason, are recorded by auditing on the server or database. Managed Instance has an error log and the query above works as it is.Where To Go Next
Which of these you need depends on the state number in the error log.
- Login Failed or Permission Denied, where to go when the state turns out not to be about the password at all
- Login Failed: Server Is in Script Upgrade Mode (Error 18401), and How Long to Wait Before You Worry, the other reason everybody is locked out at once, with no state number to read
- SELECT Permission Denied (229), the last door in the corridor this error opens
- Duplicate Key Errors (2627 / 2601), the write-side denial with the value in the message
- Set the Default Database for a Login, when the login is fine but its default database is not
- Login Failed: Untrusted Domain (18452), the Windows-auth sibling of this error
- Locked Out of SQL Server: Regain Sysadmin When Nobody Has It, when every sysadmin is gone or disabled and nobody can get in to fix it
- Login Disabled (18470), when the login exists but is switched off
- Kerberos vs NTLM, the mechanics behind most login-failure investigations
- Get Permissions and Role Membership, one login’s effective access across the instance
- Get Error Log Patterns, spot repeated login failures before someone reports them
- Get Sysadmin Members, audit who holds the keys
- Cannot Connect to SQL Server: The Checks in the Order That Finds It, the router for every connection error, start here when you are not sure which one you have
Leave a Reply