將資料庫備份還原或分離附加至新實例時,伺服器層級登入 (Login) 與資料庫層級使用者 之間的 SID (Security Identifier) 失去對應,導致原本正常的登入無法存取資料庫,拋出經典錯誤:
Msg 229, Level 14, State 1: %s permission denied on object %.*s, database %.*s, owner %.*sError 15023: User or role '%s' already exists in the current database.本文系統說明成因、診斷查詢、標準修復腳本、預防機制與自動化方案。
| 層級 | 儲存位置 | 關鍵欄位 |
|---|---|---|
| 伺服器層級 (Login) | master.sys.server_principals | sid (唯一識別) |
| 資料庫層級 (User) | user_db.sys.database_principals | sid (必須與 Login.sid 完全一致) |
還原/附加資料庫時,sys.database_principals 隨資料庫檔案移動,但 master.sys.server_principals 留在原實例。新實例若建立同名 Login,SID 為新產生,與資料庫內既有 User SID 不符 → **孤立使用者**。
-- 方法 1: 系統預存程序 (舊版相容)
EXEC sp_change_users_login 'Report';
-- 方法 2: 現代目錄檢視 (推薦,資訊更豐富)
SELECT
dp.name AS DatabaseUser,
dp.type_desc AS UserType,
dp.sid AS UserSID,
sp.name AS ServerLogin,
sp.sid AS LoginSID,
CASE WHEN sp.sid IS NULL THEN 'Orphaned' ELSE 'Mapped' END AS Status
FROM sys.database_principals dp
LEFT JOIN sys.server_principals sp ON dp.sid = sp.sid
WHERE dp.type IN ('S', 'U', 'G') -- SQL, Windows User, Windows Group
AND dp.principal_id > 4; -- 排除系統內建
-- 1. 回報孤立使用者
EXEC sp_change_users_login 'Report';
-- 2. 自動修復:若 Login 不存在則建立 (需 sysadmin)
EXEC sp_change_users_login 'Auto_Fix', 'UserName', NULL, 'StrongPassword';
-- 3. 僅對應既有同名 Login (需 Login 已存在)
EXEC sp_change_users_login 'Update_One', 'UserName', 'LoginName';
限制: 僅支援 SQL 登入,不支援 Windows 登入/群組;已棄用,未來版本移除。
-- 前提:目標 Login 已存在於新實例 (同名或不同名皆可)
ALTER USER [DatabaseUser] WITH LOGIN = [ServerLogin];
-- 或指定 SID (極少用)
ALTER USER [DatabaseUser] WITH LOGIN = [ServerLogin], SID = 0x...;
-- 僅在無法對應時最後手段
DROP USER [OrphanedUser];
CREATE USER [NewUser] FOR LOGIN [ServerLogin];
-- 之後必須:重新授權、修正 Schema 擁有權、重建資料庫角色成員資格
Windows 登入的 SID 來源於 AD/本機 SAM,**跨網域/重建網域/移轉網域** 時 SID 會改變,導致大量孤立使用者。
sp_change_users_login。ALTER USER ... WITH LOGIN 對應。sp_helprevlogin 產生建立腳本)。Microsoft 提供 sp_helprevlogin 預存程序,能產生包含 **原始 SID、密碼雜湊、預設資料庫、語言** 的 CREATE LOGIN 腳本。遷移前在舊實例執行,遷移後在新實例執行腳本,**Login SID 完美保留**,資料庫 User 即自動對應,零孤立使用者。
-- 建立/轉換為含檔資料庫
ALTER DATABASE MyDB SET CONTAINMENT = PARTIAL;
-- 建立含檔使用者 (無伺服器層級 Login,密碼存資料庫內)
CREATE USER AppUser WITH PASSWORD = 'StrongPwd';
-- 遷移/還原至任意實例即可直接連線,零 SID 問題
適用場景: 多租戶、頻繁遷移、CI/CD 環境、Always On 可用性群組次要複本可讀性。
# 使用 dbatools 模組
Copy-DbaLogin -Source OldServer -Destination NewServer -ExcludeSystemLogins
# 自動同步 SID、密碼雜湊、權限、伺服器角色
Test-DbaDbOrphanUser -SqlInstance NewServer -Database MyDB
# 驗證是否仍有孤立使用者
sp_helprevlogin 產生 Login 建立腳本。Test-DbaDbOrphanUser 或 sp_change_users_login 'Report'。ALTER USER ... WITH LOGIN。