In this post, I’m going to be looking at sp_change_users_login in order to fix SQL Server orphaned users as a continuation to a previous article. There I looked at a couple of ways to transfer logins from one SQL Server to another and touched upon the issue of the orphaned “security identifier” (SID).
A typical scenario that arises is when the DBA quickly realises that the logins on the SQL Server cannot access the database. They try and add the login to the database as a user and are presented with the error:
Error 15023: User already exists in current database.
The root cause of this problem can be when a login is deleted or the database has been moved or restored to another server but the login transported in the database does not exist on the destination server.
Through SQL Server Management Studio, the database user properties will show the User type: as SQL user without login
sp_change_users_login to the rescue!
I first saw this error a number of years ago and due to my complete lack of experience at the time, one of my first thoughts was that I would have to remove the database users, re-add them all for each login requiring access and then proceed to add the permissions back in for user.
I quickly realised that this would be a massive waste of my time and that there had to a better way and so I proceeded to consult the search engines for a resolution. Unsurprisingly I quickly found many other people who had been in the same situation as me and that sp_change_users_login had been the cure to all their woes.
And here I am writing a post about it 🙂 Well I never would have imagined that but it was a long time ago and only clever people could put a website together back in those days when blogging platforms were a twinkle in some programmers eye.
How to use sp_change_users_login to fix SQL Server orphaned users
The best thing to do is run the following code against each database you are checking. Run this against each database. It will help you to find all the orphaned logins in your database.
USE DatabaseName EXEC sp_change_users_login 'Report';
You will see output like the screenshot attached if there are any sql orphaned users. In this example, user “db_login1” is showing up as an orphaned user.
If you already have a login which you want to map your database user to, you could run the following (note that the first instance of ‘db_login1’ is the user in the database, the second instance is the login to be mapped to) :
EXEC sp_change_users_login 'update_one', 'db_login1', 'db_login1';
If you don’t already have a login to map to, you can have sp_change_users_login create one for you and with a password. The following code does this and creates a login with the same name and a password of ‘aaZZww77’ as an example.
EXEC sp_change_users_login 'Auto_Fix', 'db_login1', NULL, 'aaZZww77';
UPDATE – 3rd Apr 2018
An alternate way to detect orphaned users in SQL Server or PDW is by running this code for each database:
SELECT dp.type_desc, dp.SID, dp.name AS user_name FROM sys.database_principals AS dp LEFT JOIN sys.server_principals AS sp ON dp.SID = sp.SID WHERE sp.SID IS NULL AND authentication_type_desc = 'INSTANCE';
This is an example output:
For identifying orphaned users in Azure SQL Database and SQL Data Warehouse run this code in the master database:
SELECT sid FROM sys.sql_logins WHERE type = 'S';
Now run this code in each database:
SELECT name, sid, principal_id FROM sys.database_principals WHERE type = 'S' AND name NOT IN ('guest', 'INFORMATION_SCHEMA', 'sys') AND authentication_type_desc = 'INSTANCE';
Compare the two lists to see if there are user SID’s in sys.database_principals which are not found in sys.sql_logins
Fix SQL Orphaned Users Using CREATE LOGIN
You can take the SID’s identified in the previous section and use them as part of the CREATE LOGIN statement, example:
CREATE LOGIN db_login_1 WITH PASSWORD = 'use_a_strong_password_here', SID = 0xB171D3B5A352A846847342C5E46620BA;
If you’re mapping an orphaned user to a login which already exists in master, run this replacing db_login and svr_login accordingly:
ALTER USER db_login WITH Login = svr_login;
For more info on how to fix orphaned users, click this sp_change_users_login link and this one on troubleshooting orphaned users to view the documentation from Microsoft.
Colin Mongardi says
Thanks, for this tip. (Out of ignorance) I have always gone for the solution of deleting/remapping the user. Which is fine if they just have simple permissions. How I miss the days of when I could just ask “someone” to sort out my database woes!
Andy Hayes says
Hi Colin
I hope you are well and thanks for the comment.
I’m glad you found this post useful 🙂
All the best
Andy
Dimple says
Thanks!
Shiny says
Thanks so much for this 🙂
Shane Garven says
Thanks Andy. This has saved me today after some migrations by our DBA team from SQL 2005 to SQL 2008.
Out of interest, what level of permissions are required to ensure the login is created, if it doesn’t exist in SQL?
This worked for me. Although our cluster is locked down (as you would expect) and I was surprised it allowed me to create the login. Because I don’t think I could create it in the GUI-fashion. Server->Security->Logins->Right-Click->New Login.
Thanks again.
Andy Hayes says
Hi Shane
You need CREATE LOGIN permission to create logins in SQL Server. When you say that your cluster was locked down but you were able to create a login then the login which you authenticated to SQL Server with had/has CREATE LOGIN permission enabled.
Thanks for your comment.
Pål says
Thanks for a great article!
Want to scan your databases for orphaned users?
Try this:
EXEC sp_MSforeachdb ‘USE ? EXEC sp_change_users_login ”report”’
Andy Hayes says
Thank for the tip Pal, I’m glad you liked the article.
Taranjit Singh says
We can fix all the orphan users in the database by running through a small loop
–Authored by Taranjit Singh
–fix all orphan users
–Get info of all orphan users into a temporary table
–I am using update_one assuming login exist for all orphan users
declare @userid varchar(255)
Create Table #orphans
( UserName varchar(100),
USID nvarchar(255)
)
insert into #orphans EXEC sp_change_users_login ‘report’
–loop through all orphan users and fix those
DECLARE Fixusers CURSOR FOR
SELECT UserName
FROM #orphans
OPEN fixusers
FETCH NEXT FROM fixusers
INTO @userid
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC sp_change_users_login ‘update_one’,@userid,@userid
FETCH NEXT FROM fixusers
INTO @userid
END
CLOSE fixusers
DEALLOCATE fixusers
DROP TABLE #orphans
Andy Hayes says
Thanks Taranjit!
Yvonne says
Thank you for the tip, Andy! it just exact what I have encountered in my project of migrating SQL 2000 server to SQL 2012!
Andy Hayes says
Great! Glad this helped 🙂
Lakshmi says
Hi ANdy,
I have a question for you. I am migrating databases from 2008 to 2012. I generated the create script for all logins using the sp_help_rev_login code provided by Microsoft.Si I want to know if my thought process is ok.
First run to see if there are any orphaned users.
EXEC sp_MSforeachdb ‘USE ? EXEC sp_change_users_login ”report”’
-I am expecting that there will be due to new SID creation.
Then,
1. If all the users be orphaned?
if yes then I should run this SP_change_user_login for each login right? to make sure the logins are mapped to the users.
Another question is I have multiple logins and running this for each will be tedious.
Is the cursor code provided by taranjit the best way to go.
PLease let me know your thought on this.
Yasser says
YOU ARE AWESOME !! your page’s link must be the first link showed by google.
Thank you !
Andy Hayes says
Hey, I’m glad you like the post! 🙂
Gopinath says
Hi Andy,
When execute below query
exec sp_change_users_login ‘Auto_Fix’,’domain\username’,NULL,’password@2′
am getting below message
‘The number of orphaned users fixed by updating users was 0.
The number of orphaned users fixed by adding new logins and then updating users was 0.’
Login is not created, May I know did I missed anything?
Manish says
/*fix orphan users in one particular database */
declare @query varchar(1000)
declare @executequery cursor
set @executequery=cursor for
select ‘ sp_change_users_login ‘+CHAR(39)+’update_one’+CHAR(39)
+’,’+CHAR(39)+name+CHAR(39)+’,’+CHAR(39)+name+CHAR(39)
from sysusers
where issqluser = 1 and (sid is not null and sid 0x0) AND SUSER_SNAME(sid) IS NULL
open @executequery
fetch next from @executequery into @query
while @@fetch_status=0
begin
exec (@query)
print (@query)
fetch next from @executequery into @query
end
close @executequery;
deallocate @executequery;
/*fix orphan users in all databases except system databases */
DECLARE @DB_Name varchar(100)
DECLARE @Command nvarchar(2000)
DECLARE database_cursor CURSOR FOR
SELECT name
FROM sys.databases where database_id>4
and name not like ‘%master%’
OPEN database_cursor
FETCH NEXT FROM database_cursor INTO @DB_Name
WHILE @@FETCH_STATUS = 0
BEGIN
SELECT @Command =’
use ‘+ @DB_Name+’;
declare @query varchar(1000)
declare @executequery cursor
set @executequery=cursor for
select ” sp_change_users_login ”+CHAR(39)+”update_one”+CHAR(39)+”,”+CHAR(39)+name+CHAR(39)+”,”+CHAR(39)+name+CHAR(39)
from sysusers
where issqluser = 1 and (sid is not null and sid 0x0) AND SUSER_SNAME(sid) IS NULL
open @executequery
fetch next from @executequery into @query
while @@fetch_status=0
begin
exec (@query)
print (@query)
fetch next from @executequery into @query
end
close @executequery;
deallocate @executequery;
go’
print @Command
FETCH NEXT FROM database_cursor INTO @DB_Name
END