What it means
SQL Server checks access in two steps. Your login (the server principal) gets you onto the server;
inside each database you need a user mapped to that login, or the database has to allow guest.
You’re signed in, but in this database there’s no user for you, so USE, a three-part name such as
sales.dbo.orders, or a procedure that reaches into that database fails:
Msg 916, Level 14, State 2, Server 7732422b7f56, Line 1
The server principal "reader" is not able to access the database "sales" under the current security context.
If you name that database when you connect instead, the sign-in itself fails, with
4060 and 18456. When the server principal in the
message is a long string like S-1-9-3-1116818833-…, the statement ran under EXECUTE AS USER
(cause 3 below).
Common causes
- The login was never given a user in that database. Creating a login doesn’t create users; each database needs its own.
- An orphaned user. The database was restored or attached from another server, or the login was
dropped and re-created. A user is tied to its login by the login’s security identifier (SID), and
a new login with the same name has a new SID, so the user
appno longer belongs to the loginapp. - Database-level impersonation.
EXECUTE AS USER = …, or a procedure createdWITH EXECUTE ASa user,OWNERorSELF, is trusted only inside its own database. Reaching another database from there fails with 916, even when the real login could open it.
How to fix it
Check which databases you can open
SELECT name FROM sys.databases WHERE HAS_DBACCESS(name) = 1;
Add a user for the login
Someone with ALTER ANY USER in that database (a member of db_owner or db_accessadmin) runs:
USE sales;
CREATE USER [reader] FOR LOGIN [reader];
ALTER ROLE db_datareader ADD MEMBER [reader];
Grant what the user needs: a role such as db_datareader, or GRANT SELECT ON SCHEMA::dbo and the
like. Without permissions it can open the database but gets
error 229 on the tables.
Re-map an orphaned user
List users whose SID matches no login:
SELECT dp.name AS orphaned_user, dp.type_desc
FROM sys.database_principals AS dp
LEFT JOIN sys.server_principals AS sp ON sp.sid = dp.sid
WHERE sp.sid IS NULL
AND dp.type IN ('S', 'U', 'G')
AND dp.authentication_type_desc = 'INSTANCE';
Then point each one at its login. CREATE USER would fail, since the user exists (error 15023):
ALTER USER [app] WITH LOGIN = [app];
To avoid it next time, create the login on the new server with the same SID as on the old one
(CREATE LOGIN … WITH PASSWORD = …, SID = 0x…), so restored databases match it straight away.
Don’t cross databases under EXECUTE AS USER
Database-level impersonation stays in its database by design: Microsoft’s EXECUTE AS reference
says any attempt to reach another database under it fails. To let a procedure read another
database, sign it with a certificate and give that certificate’s user in the other database the
permission it needs (Microsoft has a tutorial on signing procedures), or drop the EXECUTE AS and
give the callers access themselves. Setting the database
TRUSTWORTHY also lifts the limit, but it lets code in that database use its owner’s server-level
rights, and Microsoft recommends leaving it off.
Reproduce it
On SQL Server 2022 (16.0.4295.3) with sqlcmd, signed in as reader, a login with a user in
database inlet but none in sales:
USE sales;
SELECT TOP (1) name FROM sales.sys.tables;
Msg 916, Level 14, State 2, Server 7732422b7f56, Line 1
The server principal "reader" is not able to access the database "sales" under the current security context.
Msg 916, Level 14, State 2, Server 7732422b7f56, Line 1
The server principal "reader" is not able to access the database "sales" under the current security context.
HAS_DBACCESS('sales') returned 0 and HAS_DBACCESS('inlet') 1. As inlet, which can open sales,
a procedure WITH EXECUTE AS 'seo_err_app' (a temporary user without a login) that counted
sales.sys.tables, and then EXECUTE AS USER = 'inlet':
Msg 916, Level 14, State 2, Server 7732422b7f56, Procedure seo_err_mssql.sales_count, Line 2
The server principal "S-1-9-3-1116818833-1203971235-3338866075-816358699" is not able to access the database "sales" under the current security context.
Msg 916, Level 14, State 2, Server 7732422b7f56, Line 2
The server principal "inlet" is not able to access the database "sales" under the current security context.
The second fails although the inlet login itself can USE sales: impersonating its user confines
it to inlet. The logins part ran on a temporary SQL Server 2022 container of our own, removed
afterwards: a new login app with no user in database shop got 916; after CREATE USER app FOR LOGIN app and a GRANT, it read the table. After DROP LOGIN app and CREATE LOGIN app again, it
got 916 once more, the orphan query listed app, CREATE USER failed with
Msg 15023 … User, group, or role 'app' already exists in the current database., and
ALTER USER app WITH LOGIN = app brought access back. SQL Server 2019 and 2025 printed the same
messages for the reader and EXECUTE AS cases.
In Inlet
Inlet doesn’t manage logins and users yet, so run the CREATE USER or ALTER USER above in a query
tab, signed in as someone allowed to. When SQL Server refuses, Inlet shows its message with
SQL Server error 916, state 2, severity 14 and links to this page.