Login Failed or Permission Denied in SQL Server

⚡If the message names a user, the network is already fine. SQL Server got far enough to look at who you are, so stop checking firewalls. Then split it once more: 18456 and 18470 mean authentication failed, nobody is logged in yet. 4060, 916, 229, 262 and 15517 mean authentication succeeded and something after it said no, so the password was never involved. The checks below are in the order that finds the fault fastest.

Which Message Do You Have?

Every login and permission failure carries a number. Find the line you are holding, take the jump on its band, and ignore the rest of the page.

MessageWhat it means
Nothing answered at all Step 1: connection or authentication
53, 40, 10061, 26No credentials were ever read. Not a security problem
Authentication failed Step 2: read the 18456 state
18456, login failed for userOne number, a dozen causes. The state says which
The login is fine, a database refused it Step 3: the database refuses
18470, the account is disabledThe login exists and is switched off
4060, 4064, cannot open databaseThe database named is not usable by this login
916, not able to access the databaseConnected to the instance, no user in that database
15023, user or role already existsAn orphaned user after a restore or a migration
Logged in, one statement denied Step 4: permission denied
229, SELECT permission was deniedOne object said no
262, CREATE DATABASE permission deniedA statement-level permission is missing
300, VIEW SERVER STATE was deniedYou cannot see what the server is doing
15517, cannot execute as the principalThe database owner no longer resolves
15138, the principal owns a schemaCleanup blocked, not access blocked
Windows authentication Step 5: domain accounts
18452, from an untrusted domainWindows authentication could not be validated
17806, cannot generate SSPI contextKerberos could not issue a ticket
Nobody can get in at all Step 6: everybody is locked out
18401, server is in script upgrade modeThe instance is finishing a patch

Two numbers do most of the damage because they get read as the same thing. 18456 means SQL Server did not accept who you are. 916 and 4060 mean it accepted you and then a database refused you. Resetting a password fixes exactly one of those.


STEP1

Step 1: Is This a Connection Failure or an Authentication Failure?

The message already tells you, and it is the only thing on this page that costs nothing to check. If it says the network path was not found, that the target machine actively refused the connection, or that it could not locate the server or instance specified, then nothing on the far side ever answered. No credentials were sent, no login was looked up and no permission was evaluated. That is a service, port, firewall or name problem, and Cannot Connect to SQL Server is the page that owns it, start to finish.

The tell is whether the message names a principal. Login failed for user 'DOMAIN\svc_app' means SQL Server received the connection, read the credentials and decided against them. From that point the network is proven working and every remaining check is a security check. Everything below assumes you are on this side of that line.


STEP2

Step 2: For 18456, Read the State From the ERRORLOG

18456 is one error number covering roughly a dozen unrelated causes, and the client is deliberately told none of them. It almost always receives State 1, because explaining the failure precisely would hand an attacker a checklist. The real state goes to the server error log, and until you have read it you are guessing.

Run this on the instance. It pulls the current error log into a table variable so one pass returns both halves of each failure, the numbered Error: line and the human Reason: line, which are written as separate entries and are close to useless apart.

SET NOCOUNT ON;
DECLARE @log TABLE (LogDate datetime2(0), ProcessInfo nvarchar(64), Text nvarchar(max));
INSERT INTO @log EXEC sys.xp_readerrorlog 0, 1;

SELECT LogDate, Text
FROM   @log
WHERE  Text LIKE 'Login failed%'
    OR Text LIKE 'Error: 18456%'
ORDER BY LogDate DESC, Text;

The two lines pair up by timestamp. Read the state off the Error: line and the cause off the Reason: line beside it, and note the client address, which is usually the fastest way to find out what is still knocking.

One failure, both halvessample output, not something to copy
08:50:15 Error: 18456, Severity: 14, State: 38. 08:50:15 Login failed for user ‘Lab1001_nodb’. Reason: Failed to open the explicitly specified database ‘Lab1001_login’. [CLIENT: 192.168.1.109]

Now take the state to the right place. The short version is below, and Troubleshoot Login Failed for User (Error 18456) decodes every state including the Azure and contained-database ones, which is where to go when yours is not in this table.

StateWhat it meansGo to
1You are not being told. The client’s copy, not the causeThe query above
2, 5No login of that name existsThe 18456 post
6A Windows login presented over SQL authenticationThe 18456 post
7Disabled login and wrong password. Two faultsStep 3
8, 9Genuinely the wrong passwordReset it, then stop
11, 12It resolves, but has no permission to connectStep 4
18MUST_CHANGE is set. The password expiredThe 18456 post
38, 40, 46The login is fine. The database it asked for is notStep 3
58A SQL login on a Windows-authentication-only instanceStep 5
62Contained database SID mismatch, after a restoreStep 3

If what you are looking at is a pattern rather than one failure, a burst of states 8 and 5 from a single address at three in the morning, treat it as a security event and not a configuration one. DBA Scripts: Get Login Security Audit summarises failed logins out of the error log by login and client so the shape is obvious, and flags weak login settings while it is in there. Microsoft’s own list of states is in MS Docs for MSSQLSERVER_18456.


STEP3

Step 3: The Login Exists and the Database Refuses It

This is the family that gets misdiagnosed most often, because several of these errors still print the words “login failed” even though authentication already succeeded. Nothing here is fixed by a password.

Cannot open database requested by the login (4060 and 4064). The connection named a database, the engine authenticated the login, and the database then turned it away: no user mapped to that login, or the database is offline, in single user mode, or spelled wrong in the connection string. The ERRORLOG records it as 18456 state 38 with the database named. Cannot Open Database Requested by the Login (Errors 4060 and 4064) covers both, and 4064 is the version where the login named no database at all and its default one is unusable, which is one ALTER LOGIN to fix.

4060 at the client, then the same event in the ERRORLOGsample output, not something to copy
Sqlcmd: Error: Microsoft ODBC Driver 18 for SQL Server : Login failed for user ‘Lab1001_nodb’.. Sqlcmd: Error: Microsoft ODBC Driver 18 for SQL Server : Cannot open database “Lab1001_login” requested by the login. The login failed.. Error: 18456, Severity: 14, State: 38. Login failed for user ‘Lab1001_nodb’. Reason: Failed to open the explicitly specified database ‘Lab1001_login’. [CLIENT: 192.168.1.109]

The server principal is not able to access the database (916). Same root cause, different surface. The login is connected to the instance and something asked about a database it has no user in, which is why Object Explorer triggers it for databases you were not even looking at. Error 916 has the full picture and the fix, which is a user mapping and never a password reset.

The account is disabled (18470). The friendliest member of the family, because it says exactly what is wrong. Enabling it is one statement; the question worth asking is why it was switched off, and modify_date in sys.server_principals dates the change. Login Failed: The Account Is Disabled (Error 18470) covers both halves. If the password is also wrong you get 18456 state 7 instead, and you have two faults to fix, not one.

Orphaned users after a restore (15023, and 18456 state 62 on contained databases). A database restored from another server brings its users with it, and their SIDs no longer match any login here. The application cannot log in, somebody tries to create the user, and the engine says the user already exists. Do not drop it. User, Group or Role Already Exists (Error 15023) explains why ALTER USER ... WITH LOGIN is the right statement, and DBA Scripts: Get Orphaned Users finds every one of them across the instance before the users do. On an Availability Group the same problem arrives by a different road, because the databases fail over and the logins do not: Creating SQL Logins on an AG Environment is the way to create them so the SIDs match on every replica.


STEP4

Step 4: The Login Works and One Statement Is Denied

By now authentication has succeeded and the database has let the principal in. What is left is authorisation on a single action, and these messages are the most precise on the whole page: they name the permission, the object, the schema and the database. Take them literally.

Before changing any grant, find out what the principal can actually do. Run this from your own session and impersonate theirs, which is far quicker than borrowing their credentials and tells you the same thing.

USE YourDatabase;
EXECUTE AS USER = 'TheUser';

SELECT USER_NAME()                                        AS RunningAs,
       HAS_PERMS_BY_NAME('dbo.YourTable','OBJECT','SELECT') AS CanSelect,
       HAS_PERMS_BY_NAME(DB_NAME(),'DATABASE','CONNECT')    AS CanConnect,
       IS_ROLEMEMBER('db_datareader')                       AS InDbDatareader;

SELECT DISTINCT permission_name
FROM   sys.fn_my_permissions('dbo.YourTable','OBJECT')
WHERE  subentity_name = '';

REVERT;
A principal that is being refusedsample output, not something to copy
RunningAs CanSelect CanConnect InDbDatareader ————– ——— ———- ————– Lab1001_reader 0 1 0 permission_name ————— (0 rows affected)

Connect is granted, select is not, and fn_my_permissions returns nothing at all for the object. That is the whole diagnosis. Trust the second query when the two disagree: it lists what is effective after role membership, inheritance and denies have all been resolved, which is the arithmetic people get wrong in their heads.

When a grant appears to do nothing, look for a DENY, because a DENY beats every GRANT no matter where the GRANT came from. This finds them.

SELECT dp.state_desc, dp.permission_name,
       OBJECT_SCHEMA_NAME(dp.major_id) + '.' + OBJECT_NAME(dp.major_id) AS ObjectName,
       pr.name AS GrantedTo
FROM   sys.database_permissions AS dp
JOIN   sys.database_principals  AS pr ON pr.principal_id = dp.grantee_principal_id
WHERE  pr.name = 'TheUser'
ORDER BY dp.state_desc DESC;

A principal in that state comes back with two rows: a GRANT of CONNECT on the database, and a DENY of SELECT on the object. The DENY is the one winning, and adding another GRANT will not change that.

Then go to the page for the message in front of you. The SELECT Permission Was Denied on the Object (Error 229) is the object-level case and the one to read on fixing at the right level, role membership ahead of schema grants ahead of object grants. CREATE DATABASE Permission Denied (Error 262) is the statement-level version, and the same message shape covers every other CREATE verb. Grant VIEW SERVER STATE is the one that stops a DBA reading the DMVs on a server they can otherwise connect to perfectly well.

Two more sit in this step because they look like permission problems and are really ownership problems. Cannot Execute As the Database Principal (Error 15517) is almost always a restored database whose owner SID no longer resolves, and it breaks jobs and EXECUTE AS rather than connections. The Database Principal Owns a Schema (Error 15138) is the one that blocks cleanup, where a user cannot be dropped because dropping it would leave a schema unowned.

For what a single login reaches across the whole instance, DBA Scripts: Get User Permissions Audit answers it one login at a time. The two functions used above are HAS_PERMS_BY_NAME and sys.fn_my_permissions in MS Docs.


STEP5

Step 5: Windows Authentication Has Its Own Failures

If the login is a domain account, three errors belong to the authentication layer rather than to SQL Server, and no amount of work inside the instance will fix them.

The login is from an untrusted domain (18452). The word domain sends everybody to the domain admins, and most of the time the domain is fine. Start at the client instead: whoami says whether the session is even running as a domain account, and an IP address in the connection string forces the NTLM path and can produce this on its own. One failing machine is a client problem. Many at once earns the call. Login Failed: The Login Is From an Untrusted Domain (Error 18452) has the sequence.

Cannot generate SSPI context, SSPI handshake failed (17806). Kerberos could not issue a ticket. Check the clock first, because five minutes of skew breaks Kerberos outright and costs nothing to rule out, then look for duplicate or missing SPNs. SSPI Handshake Failed in SQL Server (Error 17806) is the diagnosis in order.

It works when I run it locally and fails from the application server. That is usually the double hop: the client authenticates to one server, that server tries to pass the identity on to SQL Server, and NTLM cannot delegate it. The shape is distinctive, an account that works interactively and fails from a linked server or a middle tier. Kerberos vs NTLM in SQL Server has the one query that tells you which scheme your connections are really using, which is worth running before an incident rather than during one.

State 58 belongs here too. A SQL login against an instance set to Windows authentication only fails with 18456 state 58, and the fix is a decision about the server’s authentication mode, not about the login.


STEP6

Step 6: Nobody Can Get In At All

When every login is failing, including yours, the instance is usually not refusing people one at a time. It is refusing everybody for one reason.

Server is in script upgrade mode (18401). Right after a cumulative update or a service pack, SQL Server runs its upgrade scripts against the system databases before it will accept normal connections, and every login gets 18401 until it finishes. The instance is working. It is not finished starting, so watch the error log rather than the clients, and give it the time the scripts need. Once they finish, Login Failed: Server Is in Script Upgrade Mode (Error 18401), and How Long to Wait Before You Worry shows how to watch the progress in the error log and what to do when it stops moving.

Locked out with no sysadmin left. It happens: the only sysadmin account was a person who left, or a hardening change removed the local Administrators group. The honest answer is that there is a supported way back in and it needs downtime. Start the instance in single user mode with the -m startup parameter, connect from the server itself as a member of the local Administrators group, which SQL Server admits as sysadmin in that mode, create or fix a login, then restart normally. It is a short, well documented procedure, covered in MS Docs on starting SQL Server in single user mode, and the only connection allowed while it runs is yours, so plan the outage rather than improvising it.

The cheaper version of that story is knowing who holds sysadmin before anybody leaves. DBA Scripts: Get Sysadmin Members lists every member of the role including the ones that arrive through a Windows group, which is where the surprises usually are.


Frequently Asked Questions

The error says State 1. What does state 1 mean?
It means you are not being told. State 1 is what the client receives when it is not entitled to the real reason, which is almost always. The genuine state is written to the server error log at the same moment, so run the query in Step 2 on the instance and read the state off the Error: 18456 line there.
Why does resetting the password not fix it?
Because several of these errors print the words “login failed” after authentication has already succeeded. 4060, 4064 and 916 all mean the credentials were accepted and a database then refused the principal. If the ERRORLOG state is 38, 40 or 46, the password was never part of the story. Go to Step 3.
I restored a database and now the application cannot log in.
That is the orphaned user case. The database carries its users from the old server and their SIDs no longer match any login here, so the login exists, the user exists, and nothing connects them. Do not drop the user and recreate it, which throws away every permission it held. Remap it with ALTER USER [name] WITH LOGIN = [name], covered in the error 15023 post linked in Step 3.
I granted the permission and it still says permission denied.
Look for a DENY. A DENY beats every GRANT, whether the GRANT came from a direct permission, a schema, or a role the user belongs to, and it is easy to inherit one from a role nobody remembers assigning. The second query in Step 4 lists every GRANT and DENY held by one principal so you can see which is winning.
Is “login failed” the same problem as “cannot connect”?
No, and they share almost nothing. “Cannot connect” means nothing answered, so the fault is the service, the port, the firewall or the name. “Login failed” means something answered and read your credentials, which proves the network is working. If your message names a user, you are on the right page. If it does not, start at the cannot-connect router linked in Step 1.
Everybody is failing at once, not just one account. Where do I look?
Check whether the instance has just been patched, because SQL Server refuses every login with 18401 while it runs its upgrade scripts, and that resolves itself. After that, check whether the server has been switched to Windows authentication only, which fails every SQL login with state 58, and whether a Windows group that granted access was changed. Step 6 covers the patching case and the genuinely locked-out case.

Related

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *