解决Azure SQL异地副本数据库用户角色未同步导致的916错误问题
解决Azure SQL异地副本数据库用户角色未同步导致的916错误问题
嗨,我来帮你搞定这个Azure SQL异地副本的916错误!
首先给你解释下原因:Azure SQL的异地复制(geo-replication)只会同步主数据库的数据和架构对象,但服务器级的登录名和数据库内用户的关联关系不会自动同步到异地副本所在的逻辑服务器。当用户尝试连接异地副本时,因为异地服务器上没有匹配的登录名,或者登录名的SID(安全标识符)和数据库内用户的SID不匹配,就会抛出错误916。
下面是具体的解决步骤,跟着来就能搞定:
核心思路
异地副本已经同步了主库的数据库用户(因为用户属于数据库对象),我们只需要在异地副本所在的逻辑服务器上创建和主库SID完全一致的登录名,让登录名和数据库内的用户关联起来,就能正常访问并获得对应权限了。
步骤1:获取主库登录名的SID
先在主数据库所在的逻辑服务器上执行SQL,拿到目标登录名的SID:
- 如果是SQL登录(用户名+密码):
SELECT name, sid FROM sys.sql_logins WHERE name = '你的登录名';
- 如果是Azure AD登录:
SELECT name, sid FROM sys.server_principals WHERE type = 'E' AND name = '你的AD用户名(格式:域名\用户名)';
把查询结果里的SID记下来,后面要用到。
步骤2:在异地副本的逻辑服务器上创建匹配的登录名
切换到异地副本所在的逻辑服务器,执行对应的创建登录语句:
- 对于SQL登录,必须指定和主库完全相同的SID:
CREATE LOGIN [你的登录名] WITH PASSWORD = '原登录名的密码', SID = 0xxxxxxx; -- 把0xxxxxxx替换成步骤1查到的SID
- 对于Azure AD登录,直接创建即可(AD的SID会自动同步一致):
CREATE LOGIN [你的AD用户名(格式:域名\用户名)] FROM EXTERNAL PROVIDER;
步骤3:验证权限
现在让用户用该登录名连接异地副本数据库,应该就能正常访问,并且拥有主库中分配的角色权限了。你也可以在异地副本数据库里执行下面的SQL验证关联是否成功:
SELECT dp.name AS 数据库用户名, sp.name AS 服务器登录名 FROM sys.database_principals dp JOIN sys.server_principals sp ON dp.sid = sp.sid WHERE dp.name = '你的数据库用户名';
如果能查到对应关系,说明配置正确。
批量处理技巧
如果有很多用户需要同步,你可以在主库生成批量创建登录的脚本,然后在异地服务器上执行:
-- 生成SQL登录的创建脚本 SELECT 'CREATE LOGIN [' + name + '] WITH PASSWORD = ''请替换为原密码'', SID = ' + CONVERT(VARCHAR(MAX), sid, 1) + ';' FROM sys.sql_logins WHERE name NOT IN ('sa', 'NT SERVICE\SQLWriter', 'NT SERVICE\Winmgmt'); -- 排除系统登录名 -- 生成AD登录的创建脚本 SELECT 'CREATE LOGIN [' + name + '] FROM EXTERNAL PROVIDER;' FROM sys.server_principals WHERE type = 'E' AND name NOT LIKE 'AzureAD%'; -- 排除系统AD主体
记得把脚本里的临时密码替换成实际密码后再执行。
注意事项
- 后续在主库新增的登录名,需要手动在异地服务器上重复上述步骤,因为异地复制不会自动同步服务器级登录。
- 如果发生故障转移,异地副本变成新的主库,之后新增的登录名也要同步到新的异地副本服务器上。
备注:内容来源于stack exchange,提问作者Nx0Hackrix




