SQL Server 删除登录名失败全解析:15434、15170、15174 错误一站式解决
在 SQL Server 日常运维中,删除一个不再使用的登录名看似简单,但经常遇到各种依赖报错。本文整理常见错误、原因,并给出可直接复用的 T-SQL 脚本,帮助你按正确顺序清理登录名。
一、常见错误速查
| 错误号 | 报错信息 | 原因 | 解决方向 |
|---|---|---|---|
| 15434 | 无法删除登录名 'X',因为该用户当前正处于登录状态 | 有活动连接 | KILL 会话 |
| 15170 | 此登录名是 N 个作业的所有者 | SQL Agent 作业所有权 | 重新指派作业所有者 |
| 15174 | 登录名 'X' 拥有一个或多个数据库 | 数据库所有者 | 更改数据库所有者 |
| 15150 | 无法对 用户 'dbo' 执行 删除 | dbo 是数据库所有者,受保护 | 不要删除 dbo,更改数据库所有者 |
二、删除登录名的正确顺序
推荐按以下顺序操作:
- 更改该登录名拥有的数据库所有者。
- 重新指派该登录名拥有的 SQL Agent 作业。
- 终止该登录名的所有活动连接。
- 删除该登录名在各数据库中的用户(如有)。
- 删除服务器级登录名。
三、分步操作脚本
1. 转移数据库所有权(解决 15174)
-- 查询并转移数据库所有权
DECLARE @LoginName SYSNAME = N'LuoCore';
DECLARE @NewOwner SYSNAME = N'sa';
DECLARE @SQL NVARCHAR(MAX), @DBName SYSNAME;
DECLARE cur CURSOR FOR
SELECT name FROM sys.databases WHERE SUSER_SNAME(owner_sid) = @LoginName;
OPEN cur;
FETCH NEXT FROM cur INTO @DBName;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @SQL = N'ALTER AUTHORIZATION ON DATABASE::' + QUOTENAME(@DBName) + N' TO ' + QUOTENAME(@NewOwner) + N';';
EXEC sp_executesql @SQL;
PRINT '数据库 ' + @DBName + ' 所有者已改为 ' + @NewOwner;
FETCH NEXT FROM cur INTO @DBName;
END
CLOSE cur; DEALLOCATE cur;
2. 重新指派 SQL Agent 作业(解决 15170)
USE [msdb];
GO
EXEC dbo.sp_manage_jobs_by_login
@action = N'REASSIGN',
@current_owner_login_name = N'LuoCore',
@new_owner_login_name = N'sa';
GO
3. 终止活动连接(解决 15434)
DECLARE @LoginName SYSNAME = N'LuoCore';
DECLARE @SQL NVARCHAR(MAX), @spid INT;
DECLARE cur CURSOR FAST_FORWARD FOR
SELECT session_id FROM sys.dm_exec_sessions
WHERE login_name = @LoginName AND session_id <> @@SPID;
OPEN cur;
FETCH NEXT FROM cur INTO @spid;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @SQL = N'KILL ' + CAST(@spid AS NVARCHAR(10)) + N';';
BEGIN TRY
EXEC sp_executesql @SQL;
PRINT '已终止会话 ' + CAST(@spid AS NVARCHAR(10));
END TRY
BEGIN CATCH
PRINT '终止会话失败: ' + ERROR_MESSAGE();
END CATCH
FETCH NEXT FROM cur INTO @spid;
END
CLOSE cur; DEALLOCATE cur;
4. 删除登录名
DROP LOGIN [Rcominfo];
5. 如果仍报“拥有数据库用户”,先清理数据库用户
在目标数据库中执行:
USE [YourDatabase];
GO
DECLARE @UserName SYSNAME = N'LuoCore';
DECLARE @SQL NVARCHAR(MAX), @schema SYSNAME, @role SYSNAME;
-- 转移架构所有权
DECLARE cur_schema CURSOR FOR
SELECT name FROM sys.schemas WHERE principal_id = USER_ID(@UserName);
OPEN cur_schema;
FETCH NEXT FROM cur_schema INTO @schema;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @SQL = N'ALTER AUTHORIZATION ON SCHEMA::' + QUOTENAME(@schema) + N' TO [dbo];';
EXEC sp_executesql @SQL;
FETCH NEXT FROM cur_schema INTO @schema;
END
CLOSE cur_schema; DEALLOCATE cur_schema;
-- 移除角色成员
DECLARE cur_role CURSOR FOR
SELECT r.name FROM sys.database_role_members rm
JOIN sys.database_principals r ON rm.role_principal_id = r.principal_id
JOIN sys.database_principals u ON rm.member_principal_id = u.principal_id
WHERE u.name = @UserName;
OPEN cur_role;
FETCH NEXT FROM cur_role INTO @role;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @SQL = N'ALTER ROLE ' + QUOTENAME(@role) + N' DROP MEMBER ' + QUOTENAME(@UserName) + N';';
EXEC sp_executesql @SQL;
FETCH NEXT FROM cur_role INTO @role;
END
CLOSE cur_role; DEALLOCATE cur_role;
-- 删除用户
SET @SQL = N'DROP USER ' + QUOTENAME(@UserName) + N';';
EXEC sp_executesql @SQL;
四、一键整合脚本
如果确认登录名不是 dbo、不是系统账户,可按顺序执行以下整合脚本。执行前请备份,并将 @LoginName 改为实际登录名。
SET NOCOUNT ON;
DECLARE @LoginName SYSNAME = N'LuoCore';
DECLARE @NewOwner SYSNAME = N'sa';
DECLARE @SQL NVARCHAR(MAX), @DBName SYSNAME, @spid INT;
-- 1. 转移数据库所有权
DECLARE cur_db CURSOR FOR
SELECT name FROM sys.databases WHERE SUSER_SNAME(owner_sid) = @LoginName;
OPEN cur_db;
FETCH NEXT FROM cur_db INTO @DBName;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @SQL = N'ALTER AUTHORIZATION ON DATABASE::' + QUOTENAME(@DBName) + N' TO ' + QUOTENAME(@NewOwner) + N';';
EXEC sp_executesql @SQL;
PRINT '数据库 ' + @DBName + ' 所有者已改为 ' + @NewOwner;
FETCH NEXT FROM cur_db INTO @DBName;
END
CLOSE cur_db; DEALLOCATE cur_db;
-- 2. 重新指派 SQL Agent 作业
BEGIN TRY
EXEC msdb.dbo.sp_manage_jobs_by_login
@action = N'REASSIGN',
@current_owner_login_name = @LoginName,
@new_owner_login_name = @NewOwner;
PRINT 'SQL Agent 作业所有者已重新指派。';
END TRY
BEGIN CATCH
PRINT '重新指派作业失败: ' + ERROR_MESSAGE();
END CATCH
-- 3. 终止活动连接
DECLARE cur_spid CURSOR FAST_FORWARD FOR
SELECT session_id FROM sys.dm_exec_sessions
WHERE login_name = @LoginName AND session_id <> @@SPID;
OPEN cur_spid;
FETCH NEXT FROM cur_spid INTO @spid;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @SQL = N'KILL ' + CAST(@spid AS NVARCHAR(10)) + N';';
BEGIN TRY
EXEC sp_executesql @SQL;
PRINT '已终止会话 ' + CAST(@spid AS NVARCHAR(10));
END TRY
BEGIN CATCH
PRINT '终止会话失败: ' + ERROR_MESSAGE();
END CATCH
FETCH NEXT FROM cur_spid INTO @spid;
END
CLOSE cur_spid; DEALLOCATE cur_spid;
-- 4. 删除登录名
BEGIN TRY
SET @SQL = N'DROP LOGIN ' + QUOTENAME(@LoginName) + N';';
EXEC sp_executesql @SQL;
PRINT '登录名 ' + @LoginName + ' 已删除。';
END TRY
BEGIN CATCH
PRINT '删除登录名失败: ' + ERROR_MESSAGE();
END CATCH
五、注意事项
- 需要
sysadmin权限。 KILL会中断会话,生产环境请谨慎。dbo用户不能删除,只能更改数据库所有者。- 如果登录名是系统账户或
sa,不要删除。 - 删除前建议用
EXEC sp_helplogins @LoginName = N'LuoCore';检查依赖。 - 操作前备份数据库和作业配置。
总结
删除 SQL Server 登录名失败通常不是权限问题,而是依赖未清理。按“数据库所有权 → SQL Agent 作业 → 活动连接 → 数据库用户 → 登录名”的顺序处理,基本可以解决 15434、15170、15174、15150 等常见错误。

浙公网安备 33010602011771号