EXECUTE AS LOGIN vs EXECUTE AS USER: Where Impersonation Stops

EXECUTE AS LOGIN and EXECUTE AS USER look like twins, but they stop in different places. A login is a server-level identity that can travel between databases. A user belongs to one database and stays inside it. Know which one you are testing, and always REVERT when you are done.

Hair barrette holding fibers within one dish beside fibers outside

Why this trips people up

A junior DBA gets a ticket: “The report works for me but fails for the sales team.” They reach for impersonation, run EXECUTE AS USER, and everything works. Then the sales team still gets an error. The test used the wrong kind of identity, so it proved nothing.

The demo creates two small databases, SqlAuthorityDemo and SqlAuthorityOther. It also creates one server-level object, a login named DemoLogin, and removes everything at the end. The login gets a random password nobody sees, since we only impersonate it.

USE master;
DROP DATABASE IF EXISTS SqlAuthorityDemo;
DROP DATABASE IF EXISTS SqlAuthorityOther;
IF SUSER_ID(N'DemoLogin') IS NOT NULL DROP LOGIN DemoLogin;
GO
CREATE DATABASE SqlAuthorityDemo;
CREATE DATABASE SqlAuthorityOther;

DECLARE @Pwd nvarchar(50) = CONVERT(nvarchar(50), NEWID());
EXEC (N'CREATE LOGIN DemoLogin WITH PASSWORD = N''' + @Pwd + N''', CHECK_POLICY = OFF;');

Next, a table in the other database, and two users in the demo database. DemoUser is mapped to the login. ScopedUser has no login at all.

USE SqlAuthorityOther;
CREATE TABLE dbo.Secret (Id int, Note varchar(20));
INSERT dbo.Secret VALUES (1, 'other database');
GO
USE SqlAuthorityDemo;
CREATE USER DemoUser FOR LOGIN DemoLogin;
CREATE USER ScopedUser WITHOUT LOGIN;

Who are you now

Each step below switches identity, asks SUSER_SNAME for the login and USER_NAME for the database user, and then returns.

EXECUTE AS LOGIN = 'DemoLogin';
SELECT 'as login' AS step, SUSER_SNAME() AS login_name, USER_NAME() AS db_user;
REVERT;

EXECUTE AS USER = 'ScopedUser';
SELECT 'as user without login' AS step,
       CASE WHEN SUSER_SNAME() LIKE N'S-1-%' THEN N'(SID only)' ELSE SUSER_SNAME() END AS login_name,
       USER_NAME() AS db_user;
REVERT;

EXECUTE AS USER = 'DemoUser';
SELECT 'as mapped user' AS step, SUSER_SNAME() AS login_name, USER_NAME() AS db_user;
REVERT;

As the login, you are DemoLogin and the database user is DemoUser. As ScopedUser there is no login name, only a SID, which the query hides. As DemoUser, the login behind it is DemoLogin. So the user context carries the login name when a login exists.

Where the user stops

Now reach into the other database. DemoLogin has no user there yet, so this attempt should fail.

EXECUTE AS LOGIN = 'DemoLogin';
BEGIN TRY
    SELECT * FROM SqlAuthorityOther.dbo.Secret;
END TRY
BEGIN CATCH
    SELECT 'login, not mapped there' AS step, ERROR_NUMBER() AS error_number, ERROR_MESSAGE() AS message;
END CATCH;
REVERT;

Error 916 says the server principal DemoLogin is not able to access the database under the current security context. That is the usual answer when a login has no user in a database. Now map the login there, grant it the table, and try both kinds of impersonation again.

USE SqlAuthorityOther;
CREATE USER DemoUserOther FOR LOGIN DemoLogin;
GRANT SELECT ON dbo.Secret TO DemoUserOther;
GO
USE SqlAuthorityDemo;
EXECUTE AS LOGIN = 'DemoLogin';
SELECT 'as login' AS step, Id, Note FROM SqlAuthorityOther.dbo.Secret;
REVERT;

EXECUTE AS USER = 'DemoUser';
BEGIN TRY
    SELECT 'as user' AS step, Id, Note FROM SqlAuthorityOther.dbo.Secret;
END TRY
BEGIN CATCH
    SELECT 'as user' AS step, ERROR_NUMBER() AS error_number, ERROR_MESSAGE() AS message;
END CATCH;
REVERT;

The login version returns the row. The user version fails with 916 again, even though the same login is mapped in both databases. That is where impersonation stops. A user context lives inside its own database and does not carry across to another one. So if your real application reads across databases, test with EXECUTE AS LOGIN.

EXECUTE AS LOGIN or EXECUTE AS USER

Do not forget the return trip

Each EXECUTE AS adds a layer, and each REVERT removes only one. The block below stacks two. After one REVERT you are still impersonating.

DECLARE @Me sysname = SUSER_SNAME();

EXECUTE AS LOGIN = 'DemoLogin';
EXECUTE AS USER = 'DemoUser';
REVERT;
SELECT 'after one REVERT' AS step, CASE WHEN SUSER_SNAME() = @Me THEN 1 ELSE 0 END AS back_to_original, USER_NAME() AS db_user;
REVERT;
SELECT 'after two REVERTs' AS step, CASE WHEN SUSER_SNAME() = @Me THEN 1 ELSE 0 END AS back_to_original, USER_NAME() AS db_user;

After the first REVERT, back_to_original is 0 and the user is still DemoUser. After the second, it is 1 and you are dbo again. A forgotten layer makes your next diagnostic fail for reasons that look unrelated. Always finish by checking who you are. The last block removes the demo, including the login.

USE master;
DROP DATABASE IF EXISTS SqlAuthorityDemo;
DROP DATABASE IF EXISTS SqlAuthorityOther;
DROP LOGIN DemoLogin;

One more rule. Do not widen trust settings or permissions just to make a test pass. Fix the real mapping instead.

Next time a user says it fails for them, test as the right kind of identity.

An impersonated context is not the original connection, it is a scoped identity needing a return.

Published by Pinal Dave on SQLAuthority. More of my work at pinaldave.com.


Discover more from SQL Authority with Pinal Dave

Subscribe to get the latest posts sent to your email.

, SQL Server, SQL User Group
Previous Post
SQL SERVER – Msg 1833 – File Cannot be Reused Until After the Next BACKUP LOG Operation
Next Post
SQL SERVER – View Column Dependencies and Output Columns

Related Posts

Leave a Reply

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

Fill out this field
Fill out this field
Please enter a valid email address.