SQL Server 删除登录名失败全解析:15434、15170、15174 错误一站式解决

在 SQL Server 日常运维中,删除一个不再使用的登录名看似简单,但经常遇到各种依赖报错。本文整理常见错误、原因,并给出可直接复用的 T-SQL 脚本,帮助你按正确顺序清理登录名。

一、常见错误速查

错误号 报错信息 原因 解决方向
15434 无法删除登录名 'X',因为该用户当前正处于登录状态 有活动连接 KILL 会话
15170 此登录名是 N 个作业的所有者 SQL Agent 作业所有权 重新指派作业所有者
15174 登录名 'X' 拥有一个或多个数据库 数据库所有者 更改数据库所有者
15150 无法对 用户 'dbo' 执行 删除 dbo 是数据库所有者,受保护 不要删除 dbo,更改数据库所有者

二、删除登录名的正确顺序

推荐按以下顺序操作:

  1. 更改该登录名拥有的数据库所有者。
  2. 重新指派该登录名拥有的 SQL Agent 作业。
  3. 终止该登录名的所有活动连接。
  4. 删除该登录名在各数据库中的用户(如有)。
  5. 删除服务器级登录名。

三、分步操作脚本

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 等常见错误。

posted @ 2026-09-18 11:22  LuoCore  阅读(8)  评论(0)    收藏  举报