User, Group or Role Already Exists in the Current Database (Error 15023)

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

Msg 15023  ·  Level 16  ·  State 1
User, group, or role ‘AppUser’ already exists in the current database. Msg 15023, Level 16, State 1
Do not drop the user. ALTER USER [name] WITH LOGIN = [name]; remaps it to the login and keeps every permission it already had.

You restored a database from another server, the application cannot log in, so you tried to create the user and SQL Server told you it is already there. Both things are true. The user exists in the database and the login exists on the server, and they are not connected to each other.


Why This Happens

Logins and users are matched by SID, not by name. A login lives on the server, a user lives in the database, and the user row stores the SID of the login it belongs to.

Restore that database onto a different server and the user comes with it, still holding the SID of a login that only existed on the old machine. The name matches. The SID does not. The user is orphaned.

Windows logins usually survive this, because their SID comes from Active Directory and is the same everywhere. SQL logins almost never do, because their SID was generated on the original instance.


Find Every Orphan First

Before fixing one, see the whole picture:

SELECT  dp.name          AS database_user,
        dp.type_desc,
        dp.sid,
        dp.create_date
FROM    sys.database_principals dp
LEFT JOIN sys.server_principals sp ON sp.sid = dp.sid
WHERE   sp.sid IS NULL
  AND   dp.type IN ('S', 'U', 'G')          -- SQL user, Windows user, Windows group
  AND   dp.name NOT IN ('guest', 'INFORMATION_SCHEMA', 'sys', 'dbo')
ORDER   BY dp.name;

Anything listed has permissions inside the database and no way to be reached from outside it.


The Fix

If a login with the same name already exists on the server, point the user at it:

USE YourDb;
GO
ALTER USER [AppUser] WITH LOGIN = [AppUser];

That rewrites the user’s SID to match the login and keeps every permission the user already had. This is the fix in almost every case.

If the login does not exist yet, create it and then remap:

CREATE LOGIN [AppUser] WITH PASSWORD = N'<a real password>';
GO
USE YourDb;
GO
ALTER USER [AppUser] WITH LOGIN = [AppUser];

Do not drop the user. Dropping it destroys its role memberships and object-level permissions, and recreating the user gives you an empty one. People do this because CREATE USER failed and dropping seems like the way to make it succeed. It is the expensive way.


Keeping the Original Password

Recreating a SQL login with a new password breaks every application using the old one. If you still have access to the source server, copy the hash instead of inventing a password:

-- ON THE SOURCE SERVER
SELECT  name,
        [sid],
        password_hash
FROM    sys.sql_logins
WHERE   name = N'AppUser';

Then on the target, create the login with the original SID so nothing needs remapping at all:

CREATE LOGIN [AppUser]
    WITH PASSWORD   = 0x0200... HASHED,
         SID        = 0x1234...,
         CHECK_POLICY = OFF;

Creating the login with the original SID is the cleanest migration, because the users in every restored database match it immediately and there is nothing to fix afterwards.


The Old Advice You Will Find

Search results still recommend:

EXEC sp_change_users_login 'Auto_Fix', 'AppUser';

It is deprecated and it guesses. Auto_Fix matches by name, which is exactly the assumption that causes trouble when two different accounts share a name across servers. ALTER USER ... WITH LOGIN is explicit, supported, and does the same job without guessing.


Stopping It Recurring

  • Script logins with their SID and hash as part of any migration, so users land already matched.
  • Run the orphan query after every restore from another server. It takes seconds and it finds the problem before an application does.
  • Prefer Windows authentication where you can. AD SIDs are consistent across servers, so the whole class of problem does not arise.

Common Questions

Should I just drop the user and recreate it?
No. Dropping destroys the role memberships and object permissions the user already had, and the recreated one is empty. ALTER USER ... WITH LOGIN remaps it and keeps everything.
Why do Windows logins usually survive a restore?
Their SID comes from Active Directory and is the same on every server. A SQL login SID is generated on the instance that created it, so it does not match anywhere else.
What about sp_change_users_login Auto_Fix?
Deprecated, and it matches by name, which is the guess that causes trouble when two different accounts share a name across servers. ALTER USER ... WITH LOGIN is explicit and supported.

Related Scripts

Comments

Leave a Reply

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