How to Fix MSSQL Error 15023: "User already exists in current database" and Stored Procedures for Preventing MSSQL Orphan Users
Whether you are using MSSQL 2005, MSSQL 2008 or MSSQL 2012, orphaned users are common when restoring a database. It happens like this: you restore the database successfully. Being a thorough and awesome database administrator, you check the user mappings for the owner/primary database user assigned to the database, and see that the user exists in your server instance, but is no longer assigned the correct mappings. You attempt to restore the mappings, but when you do, the MSSQL server responds with the error below
USE YourDB
GO
EXEC sp_change_users_login ' update_one', '$USERNAME', '$ USERNAME'
GO
2) If the account you are authenticated as has the permission to drop other users, run the query below. This will just drop the user, then you can use Object Explorer to go to Security --> Logins --> username and update the user mapping using the GUI. If you're the SA, this is the easiest option.
CREATE PROCEDURE dbo.spDBA_ FixOrphanUsers
AS
DECLARE @username VARCHAR(25)
DECLARE GetOrphanUsers CURSOR
FOR
SELECT UserName = name
FROM sysusers
WHERE issqluser = 1
AND (sid IS NOT NULL
AND sid <> 0x0)
AND SUSER_SNAME(sid) IS NULL
ORDER BY name
OPEN GetOrphanUsers
FETCH NEXT
FROM GetOrphanUsers
INTO @username
WHILE @@FETCH_STATUS = 0
BEGIN
IF @username='dbo'
EXEC sp_changedbowner 'sa'
ELSE
EXEC sp_change_users_login ' update_one', @username, @ username
FETCH NEXT
FROM GetOrphanUsers
INTO @username
END
CLOSE GetOrphanUsers
DEALLOCATE GetOrphanUsers
GO
Example 2:
CREATE PROCEDURE dbo.spDBA_ FixOrphanUsersPassWord
AS
DECLARE @username VARCHAR(25)
DECLARE @password VARCHAR(25)
DECLARE GetOrphanUsers CURSOR
FOR
SELECT UserName = name
FROM sysusers
WHERE issqluser = 1
AND (sid IS NOT NULL
AND sid <> 0x0)
AND SUSER_SNAME(sid) IS NULL
ORDER BY name
OPEN GetOrphanUsers
FETCH NEXT
FROM GetOrphanUsers
INTO @username
SET @password = @username
WHILE @@FETCH_STATUS = 0
BEGIN
IF @username='dbo'
EXEC sp_changedbowner 'sa'
ELSE
EXEC sp_change_users_login ' Auto_Fix', @username, NULL, @password
FETCH NEXT
FROM GetOrphanUsers
INTO @username
END
CLOSE GetOrphanUsers
DEALLOCATE GetOrphanUsers
GO
Example 3:
Finally, this Stored Procedure will drop all the Orphan users in database. You must recreate them manually if they are needed
CREATE PROCEDURE dbo.spDBA_ DropOrphanUsers
AS
DECLARE @username VARCHAR(25)
DECLARE GetOrphanUsers CURSOR
FOR
SELECT UserName = name
FROM sysusers
WHERE issqluser = 1
AND (sid IS NOT NULL
AND sid <> 0x0)
AND SUSER_SNAME(sid) IS NULL
ORDER BY name
OPEN GetOrphanUsers
FETCH NEXT
FROM GetOrphanUsers
INTO @username
WHILE @@FETCH_STATUS = 0
BEGIN
IF @username='dbo'
EXEC sp_changedbowner 'sa'
ELSE
EXEC sp_dropuser @username
FETCH NEXT
FROM GetOrphanUsers
INTO @username
END
CLOSE GetOrphanUsers
DEALLOCATE GetOrphanUsers
GO
Error 15023: "User already exists in current database"
Below are a series or commands that can be used to immediately resolve errors like this, followed by a series of stored procedures that can be used in a number of ways to keep your MSSQL instance orphan-free on a more long-term basis.
The scripts below assume a number of variables. Keep these in mind and replace them with the correct values before executing the respective queries. The $ character is here intended as a variable notation only and is not to be included in our queries. These are used to distinguish them from alternative notation such as @fn that will appear later in the article
$DATABASE = the name of your database
$USERNAME = username for $DATABASE
$PASSWORD = password for $USERNAME
Option 1) Right click the database instance name in Object Explorer and hit Run Query. The script below will return all the existing users in the database so that you can confirm the existence of orphans as needed.
USE $DATABASE
GO
EXEC sp_change_users_login ' Report'
GO
Run the following to associate the database login with the username. ‘Auto_Fix’ attribute will create the user in SQL Server instance if it does not exist correctly already. Auto-Fix links a user entry in the sysusers table in the current database to a login of the same name in sysxlogins.
GO
EXEC sp_change_users_login '
GO
Run the following to associate the database login with the username. ‘Auto_Fix’ attribute will create the user in SQL Server instance if it does not exist correctly already. Auto-Fix links a user entry in the sysusers table in the current database to a login of the same name in sysxlogins.
USE $DATABASE
GO
EXEC sp_change_users_login ' Auto_Fix', '$USERNAME', NULL, '$PASSWORD'
GO
This query will also associate the login with the username. ‘Update_One’ links the specified user in the current database to the login, however in this instance the login must already exist. User and login must be specified (in this example they match - note that username and login can differ, but really should not during the course of standard administration). Password must be NULL or not specified, but can be reset later.
GO
EXEC sp_change_users_login '
GO
This query will also associate the login with the username. ‘Update_One’ links the specified user in the current database to the login, however in this instance the login must already exist. User and login must be specified (in this example they match - note that username and login can differ, but really should not during the course of standard administration). Password must be NULL or not specified, but can be reset later.
USE YourDB
GO
EXEC sp_change_users_login '
GO
2) If the account you are authenticated as has the permission to drop other users, run the query below. This will just drop the user, then you can use Object Explorer to go to Security --> Logins --> username and update the user mapping using the GUI. If you're the SA, this is the easiest option.
USE @DATABASE
GO
EXEC sp_dropuser '$USERNAME'
GO
GO
EXEC sp_dropuser '$USERNAME'
GO
Now that we have a resolution for orphan users in the short term, let's explore some examples of stored procedures that can be used to fix orphan users. These stored procedures can be run as a scheduled task to address this issue on a regular ongoing basis withoutthe need for the DBA to take special action.
Example 1:
This Stored Procedure will fix all the Orphan users in your database by mapping them to usernames that already exist for that user on the server. This stored procedure can be used when user has been created at server level but does not show up as a user in database.
CREATE PROCEDURE dbo.spDBA_
AS
DECLARE @username VARCHAR(25)
DECLARE GetOrphanUsers CURSOR
FOR
SELECT UserName = name
FROM sysusers
WHERE issqluser = 1
AND (sid IS NOT NULL
AND sid <> 0x0)
AND SUSER_SNAME(sid) IS NULL
ORDER BY name
OPEN GetOrphanUsers
FETCH NEXT
FROM GetOrphanUsers
INTO @username
WHILE @@FETCH_STATUS = 0
BEGIN
IF @username='dbo'
EXEC sp_changedbowner 'sa'
ELSE
EXEC sp_change_users_login '
FETCH NEXT
FROM GetOrphanUsers
INTO @username
END
CLOSE GetOrphanUsers
DEALLOCATE GetOrphanUsers
GO
Example 2:
This stored procedure will fix the Orphans in your database by creating a new user on your MSSQL server instance with the same password as the database orphan. Don't forget to change all the passwords once users have been created
CREATE PROCEDURE dbo.spDBA_
AS
DECLARE @username VARCHAR(25)
DECLARE @password VARCHAR(25)
DECLARE GetOrphanUsers CURSOR
FOR
SELECT UserName = name
FROM sysusers
WHERE issqluser = 1
AND (sid IS NOT NULL
AND sid <> 0x0)
AND SUSER_SNAME(sid) IS NULL
ORDER BY name
OPEN GetOrphanUsers
FETCH NEXT
FROM GetOrphanUsers
INTO @username
SET @password = @username
WHILE @@FETCH_STATUS = 0
BEGIN
IF @username='dbo'
EXEC sp_changedbowner 'sa'
ELSE
EXEC sp_change_users_login '
FETCH NEXT
FROM GetOrphanUsers
INTO @username
END
CLOSE GetOrphanUsers
DEALLOCATE GetOrphanUsers
GO
Example 3:
Finally, this Stored Procedure will drop all the Orphan users in database. You must recreate them manually if they are needed
CREATE PROCEDURE dbo.spDBA_
AS
DECLARE @username VARCHAR(25)
DECLARE GetOrphanUsers CURSOR
FOR
SELECT UserName = name
FROM sysusers
WHERE issqluser = 1
AND (sid IS NOT NULL
AND sid <> 0x0)
AND SUSER_SNAME(sid) IS NULL
ORDER BY name
OPEN GetOrphanUsers
FETCH NEXT
FROM GetOrphanUsers
INTO @username
WHILE @@FETCH_STATUS = 0
BEGIN
IF @username='dbo'
EXEC sp_changedbowner 'sa'
ELSE
EXEC sp_dropuser @username
FETCH NEXT
FROM GetOrphanUsers
INTO @username
END
CLOSE GetOrphanUsers
DEALLOCATE GetOrphanUsers
GO
(Hat tip to Pinal Dave)