The Server Principal Is Not Able to Access the Database (Error 916)

🚨Part of the SQL Server Errors series, the exact messages and what actually causes them.

Msg 916  ·  Level 14  ·  State 2
The server principal “ErrDemo916” is not able to access the database “DemoDatabase” under the current security context.
Check the database, not the login: the named database has no user mapped to this principal, or its CONNECT was revoked. Object Explorer often triggers it for databases other than the one you opened; the fix is a user mapping, not a password.

The login worked. That is the part that throws people. Authentication is already done by the time 916 fires, so resetting the password or checking the login’s status gets you nowhere. What failed is the next step: the server principal tried to enter a specific database, and that database has no user for it to become.


Why This Happens

Three situations produce this one error, and they take three different fixes. The server has already let you in by this point; 916 is a database refusing you, so the answer is always inside that database or inside the tool that asked.

No User Mapped to the LoginMOST COMMON

A login and a database user are two different principals joined by a SID. If nothing in the database carries the login’s SID, the join fails and the database refuses you. The login may be perfectly valid at the server door: 916 is the database saying no, not the server.

How you tell

The query below returns no row whose mapped_login is your login. A user that was dropped while the login lived on looks identical here, and takes the same fix, which is why they are one case rather than two.

CONNECT Denied or RevokedCOMMON

The user exists and the mapping is intact, but the permission that lets it in has been taken away. This is the case that confuses people, because everything looks correctly configured until you check the permission itself.

How you tell

The user IS in the list below with your login in mapped_login, and sys.database_permissions shows CONNECT with state_desc = 'DENY', or simply has no GRANT row for CONNECT at all.

SSMS Asked on Your BehalfVERY COMMON IN PRACTICE

The special case that generates most of the search traffic. Expanding the Databases node makes Object Explorer quietly query every database on the instance for the detail columns it displays, size and collation among them. One database your login cannot reach fails that background query, and SSMS raises 916 about a database you never clicked.

How you tell

The error names a database you did not open, and it arrives while expanding a node rather than while running a query. Microsoft documents a second trigger with the same shape: CONNECT denied on msdb breaks the Policy Based Management query, and 916 arrives next to a “Failed to retrieve data for this request” dialog.

Microsoft’s reference covers error 916 in full, including the Object Explorer triggers.


Reproduce It in One Batch

This is the exact test I ran to capture the message above, and it doubles as a diagnostic for any login you are troubleshooting:

-- a login that exists on the server and has no user in the target database
CREATE LOGIN ErrDemo916 WITH PASSWORD = '<a strong password>';

EXECUTE AS LOGIN = 'ErrDemo916';
SELECT TOP 1 order_id FROM DemoDatabase.dbo.RlsOrders;
REVERT;

DROP LOGIN ErrDemo916;

That SELECT throws Msg 916, Level 14, State 2 every time, which is the message in the box above. EXECUTE AS is what makes this useful on a real instance: it lets you test as the affected principal without knowing their password, so you can confirm a report of 916 without asking anyone to hand over credentials.


Find the Gap

Check whether the login has a user in the database, and what that user can do:

USE DemoDatabase;
SELECT dp.name        AS database_user,
       dp.type_desc,
       sp.name        AS mapped_login,
       dp.authentication_type_desc
FROM sys.database_principals dp
LEFT JOIN sys.server_principals sp ON sp.sid = dp.sid
WHERE dp.type IN ('S', 'U', 'G')
ORDER BY dp.name;

No row with your login’s name in mapped_login means no mapping. A row whose database_user exists but whose CONNECT was revoked shows up in sys.database_permissions with state_desc = 'DENY' or simply no GRANT row for CONNECT.


The Fix

No user mapped to the login. Create the mapping and give it what it needs:

USE DemoDatabase;
CREATE USER ErrDemo916 FOR LOGIN ErrDemo916;
ALTER ROLE db_datareader ADD MEMBER ErrDemo916;

CONNECT denied or revoked. Give the permission back:

GRANT CONNECT TO ErrDemo916;

SSMS asked on your behalf. Two honest options: grant the login access to the database SSMS is choking on, or stop SSMS asking the question. In Object Explorer Details (F7), right-click the column headers and remove Collation and the size columns, and the background query that triggers 916 stops running. Granting access is the fix; trimming the columns is the workaround when access is genuinely not supposed to exist.


When It Is Not This

If the database is OFFLINE, RESTORING, SUSPECT or already in SINGLE_USER you get different errors (942, 927, 926 and 924 respectively), not 916. And if the login itself failed you are in 18456 territory before any of this starts. 916 specifically means: server let you in, database did not.


Common Questions

Is this the same as login failed (18456)?
No. 18456 means the server door did not open, authentication itself failed. 916 fires after a successful login: the server let the principal in and one specific database refused it. Password resets cannot fix it.
Why does SSMS raise this for a database I never clicked?
Object Explorer queries every database for the detail columns it displays, size and collation included. If your login lacks access to any one database, that background query fails and SSMS surfaces 916 about a database you never touched. Remove those columns from Object Explorer Details or grant the access.
Can I just enable the guest user?
It makes the error go away by giving every login access to the database, which is why it shows up in security audits. Map a real user for the login instead; guest is the workaround that becomes a finding.
The error came from an application with ODBC state 08004, not from SSMS.
Then the code changed database after connecting: a USE, a three-part name such as OtherDb.dbo.Table, or a procedure that reaches into another database. That is the shape reproduced above. A database named in the connection string itself fails earlier and differently, with 4060, so 916 from an application points at a statement, not at the connection string.

Related Scripts

Comments

Leave a Reply

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