使用 Windows 身份验证连接 SQL Server 时出现“无法生成 SSPI 上下文”错误

适用于:   SQL Server
原始 KB 编号: 811889

备注

在开始故障排除之前,我们建议查看先决条件并核对清单。

使用 Windows 身份验证远程连接 SQL Server 实例时,会收到以下错误消息:

目标主体名称不正确。 无法生成 SSPI 上下文。

常见问题解答

什么是 SSPI?

安全支持提供程序接口 (SSPI) 是一组 Windows API,允许通过任何泛型数据传输层(例如 TCP/IP 套接字)进行委派和相互身份验证。 一个或多个软件模块提供实际的身份验证功能。 每个模块被称为安全支持提供程序 (SSP),并被实现为动态链接库 (DLL)。

什么是 Kerberos?

Kerberos v5 协议是行业标准的安全包,是 Windows 操作系统中的三个安全包之一。 有关更多信息,请参阅安全支持提供程序 (SSP)

“无法生成 SSPI 上下文”错误意味着什么?

此错误意味着 SSPI 尝试但无法使用 Kerberos 身份验证通过 TCP/IP 或命名管道将客户端凭据委托给 SQL Server。 在大多数情况下,配置错误的服务主体名称 (SPN) 会导致此错误。

什么是 SPN?

服务主体名称 (SPN) 是服务实例的唯一标识符。 Kerberos 身份验证使用 SPN 将服务实例与服务登录帐户相关联。 此关联过程允许客户端应用程序请求服务对帐户进行身份验证,即使客户端没有帐户名称。

例如,运行 SQL Server 实例的服务器的典型 SPN 如下所示:

MSSQLSvc/SQLSERVER1.northamerica.corp.mycompany.com:1433

默认实例的 SPN 格式与命名实例的 SPN 相同。 端口号用于将 SPN 与特定实例关联起来。 有关注册 SQL Server 服务 SPN 的详细信息,请参阅注册 Kerberos 连接的服务主体名称

为什么 SSPI 使用 NTLM 或 Kerberos 身份验证?

Windows 身份验证是用户向 SQL Server 进行身份验证的首选方法。 使用 Windows 身份验证的客户端使用 NTLM 或 Kerberos 进行身份验证。

当 SQL Server 客户端通过 TCP/IP 套接字对运行 SQL Server 的远程服务器使用集成安全性时,SQL Server 客户端网络库使用 SSPI API 来执行安全委派。 SQL Server 网络客户端调用 AcquireCredentialsHandle 函数,并传入 pszPackage 参数的“negotiate”。 此过程通知基础安全提供程序协商委派。 在此上下文中,“negotiate”是指在基于 Windows 的计算机上尝试 Kerberos 或 NTLM 身份验证。 换句话说,如果运行 SQL Server 的目标计算机具有关联且配置正确的 SPN,Windows 将使用 Kerberos 委派。 否则,Windows 将使用 NTLM 委派。 如果 SQL Server 客户端在 SQL Server 所在的同一台计算机上进行本地连接,则始终使用 NTLM。

为什么连接在遇到 Kerberos 问题后不会故障转移到 NTLM?

当驱动程序使用 Windows 身份验证连接到 SQL Server 时,客户端上的 SQL Server 驱动程序代码使用 WinSock 网络 API 来解析服务器的完全限定 DNS。 为执行此操作,驱动程序代码调用 gethostbynamegethostbyaddr WinSock API。 如果使用集成安全性,即使 IP 地址或主机名作为服务器名称传递,驱动程序也会尝试解析服务器的完全限定 DNS。

当客户端上的 SQL Server 驱动程序解析服务器的完全限定 DNS 时,相应的 DNS 用于为服务器形成 SPN。 因此,WinSock 将 IP 地址或主机名解析为完全限定 DNS 时出现的问题可能导致 SQL Server 驱动程序为服务器创建无效的 SPN。

例如,客户端 SQL Server 驱动程序可以用作完全限定的 DNS 来解析无效的 SPN,如下所示:

  • MSSQLSvc/SQLSERVER1:1433
  • MSSQLSvc/123.123.123.123:1433
  • MSSQLSvc/SQLSERVER1.antartica.corp.mycompany.com:1433
  • MSSQLSvc/SQLSERVER1.dns.northamerica.corp.mycompany.com:1433

当 SQL Server 驱动程序形成无效的 SPN 时,身份验证仍然有效,因为 SSPI 接口尝试在 Active Directory 服务中查找 SPN。 如果 SSPI 接口找不到 SPN,则不执行 Kerberos 身份验证。 此时,SSPI 层切换到 NTLM 身份验证模式,登录使用 NTLM 身份验证,通常会成功。 如果 SQL Server 驱动程序形成的有效 SPN 未分配给相应容器,则驱动程序会尝试 SPN,但无法使用它。 在这种情况下,可能会出现“无法生成 SSPI 上下文”的错误。 如果 SQL Server 启动帐户是本地系统帐户,则合适的容器是计算机名称。 对于任何其他帐户,合适的容器是 SQL Server 启动帐户。 身份验证使用它找到的第一个 SPN,因此请确保没有将 SPN 分配到错误的容器。 换句话说,每个 SPN 只能分配到一个容器。

如何验证连接的身份验证方法?

若要确定连接的身份验证方法,请运行以下查询:

SELECT net_transport, auth_scheme   
FROM sys.dm_exec_connections   
WHERE session_id = @@SPID;  

有关详细信息,请参阅使用 Kerberos 身份验证确定我是否已连接到SQL Server

如何为 SQL Server 创建 SPN?

当启动 SQL Server 数据库引擎的实例时,SQL Server 使用 DsWriteAccountSpn API 尝试自动注册 SQL Server 服务的 SPN。 如果 SQL Server 服务帐户在 Active Directory 中具有servicePrincipalName读取和写入servicePrincipalName权限,则此调用会成功。 否则,需要 Active Directory 管理员使用 Microsoft Kerberos Manager for SQL Server 或内置 Setspn 工具手动注册正确的 SPN。 有关管理 SQL Server SPN 的详细信息,请参阅注册 Kerberos 连接的服务主体名称

备注

此过程仅适用于你一直收到这些错误消息,而不是间歇性收到消息的情况。

Kerberos 连接失败的原因有很多,例如配置错误的 SPN、名称解析问题或 SQL Server 服务启动帐户权限不足。 Microsoft Kerberos 配置管理器 (KCM) 是一种有助于检查错误原因的工具。 KCM 还提供用于修复进程中任何已识别问题的选项。

按照以下步骤使用 KCM 修复错误。

  1. 在遇到连接问题的计算机上,下载并安装 Kerberos 配置管理器

  2. 从“%SystemDrive%:\Program Files\Microsoft\Kerberos Configuration Manager”文件夹启动“KerberosConfigMgr.exe”。 然后,使用具有权限的域帐户连接到你无法连接的 SQL Server 计算机。

  3. 选择“连接”,如果在 SQL Server 计算机上运行 KCM,则将适用于场景的服务器名称和其他详细信息留空。 选择“连接”以执行分析。 KCM 完成检索所需信息后,会自动切换到“SPN”选项卡,默认显示 SQL Server、SQL Server Reporting Services、Analysis Services 和 AG 侦听器的信息。 若要排查此错误,请取消选中除 SQL Server 以外的所有内容。

  4. 使用“状态”列从工具中查看诊断,并按照相关步骤解决问题:

    状态 更多信息 操作
    Good 选中的项已正确配置。 可以转到输出中的下一项。 无需采取任何行动
    缺少所需的 SPN 当 Active Directory 中 SQL Server 启动帐户缺少“所需的 SPN”列中标识的 SPN 时,将报告此状态。 1. 选择“修复”以查看“警告”对话框中的信息。
    2. 选择“是”将缺少的 SPN 添加到 Active Directory。
    3. 如果域帐户具有更新 Active Directory 所需的权限,则所需的 SPN 将添加到 Active Directory。
    4. 如果域帐户没有更新 Active Directory 所需的权限,请使用“生成”或“全部生成”以生成脚本,从而帮助 Active Directory 管理员添加缺少的 SPN。
    5. 添加 SPN 后,再次运行 Kerberos 配置管理器验证 SPN 问题是否已解决。
    必须启用 TCP 才能使用 Kerberos 配置 当未在客户端计算机上启用 TCP 时,会发生这种情况。 若要为 SQL Server 实例启用 TCP/IP 协议,请执行以下步骤:
    1. 在 SQL Server 配置管理器的“控制台”窗格中,展开“SQL Server 网络配置”。
    2. 在“控制台”窗格中,选择<instance name>“协议”。
    3. 在“详细信息”窗格中,右键单击“TCP/IP”,然后选择“启用”。
    4. 在“控制台”窗格中,选择“SQL Server 服务”。
    5. 在“详细信息”窗格中,右键单击 SQL Server (<instance name>),然后选择“重启”以停止并重启 SQL Server 服务。
    有关详细信息,请参阅启用或禁用服务器网络协议
    动态端口 此消息针对使用动态端口的命名实例显示(默认配置)。 在需要使用 Kerberos 连接到 SQL Server 的环境中,应将命名实例设置为静态端口,并在注册 SPN 时使用该端口。 要将 SQL Server 实例配置为使用静态端口,请执行以下步骤:
    1. 在 SQL Server 配置管理器的“控制台”窗格中,展开“SQL Server 网络配置”,展开 <instance name> 协议,然后双击“TCP/IP”。
    2. 在“TCP/IP 属性”对话框中,查看“协议”选项卡上的“全部侦听”设置。
    3. 如果“全部侦听”设置设置为“是”,请切换到“IP 地址”选项卡并滚动到 Windows 底部以查找 IPAll 设置。 删除“TCP 动态端口”中包含的当前值,并在“TCP 端口”字段中设置所需的值。 选择“确定”并重启 SQL Server 实例,使设置生效。
    4. 如果“全部侦听”设置设置为“否”,请切换到“IP 地址”选项卡,并检查 IP1、IP2 中显示的每个 IP 地址。 对于已启用的 IP 地址,请删除“TCP 动态端口”字段中包含的当前值,并在“TCP 端口”字段中设置所需的值。 选择“确定”并重启 SQL Server 实例,使设置生效。
    有关详细信息,请参阅配置服务器以侦听特定 TCP 端口
    重复的 SPN 当同一 SPN 在 Active Directory 中的不同帐户下注册时,可能会遇到这种情况。 1. 选择“修复”按钮,查看“警告”对话框中的信息,如果可以将缺少的 SPN 添加到 Active Directory,请选择“是”。
    2. 如果域帐户具有更新 Active Directory 所需的权限,则将删除错误的 SPN。
    3. 如果域帐户没有更新 Active Directory 的必要权限,请使用“生成”或“生成所有”按钮生成必要的脚本,可以将该脚本交给 Active Directory 管理员以删除重复的 SPN。 删除 SPN 后,重新运行 KCM 以验证 SPN 问题是否已解决。

    备注

    如果启动 KCM 的域帐户没有在 Active Directory 中操作 SPN 的权限,则可以使用“SPN 脚本”列下的相应“生成”或“生成所有”按钮生成所需的命令,并与 Active Directory 管理员协作来修复由 KCM 标识的问题。

  5. 修复 KCM 中标识的所有问题后,请重新运行该工具。 确保未报告其他问题,然后重试连接。 如果该工具仍报告问题,请重复上一过程。

修复了没有 Kerberos 配置管理器的错误

如果无法使用 KCM,请执行以下步骤:

步骤 1:使用 ping 命令检查名称解析

使 Kerberos 身份验证成功的关键因素是网络上的有效 DNS 功能。 可以使用 Ping 命令提示符实用工具在客户端和服务器上验证此功能。 在客户端计算机上,运行以下命令获取运行 SQL Server(计算机名称为 SQLServer1)的服务器的 IP 地址:

ping sqlserver1

要查看 Ping 实用工具是否解析 SQLServer1 的完全限定的 DNS,请运行以下命令:

ping -a <IPAddress>

例如:

C:\>ping SQLSERVER1

Pinging SQLSERVER1 [123.123.123.123] with 32 bytes of data:

Reply from 123.123.123.123: bytes=32 time<10ms TTL=128
Reply from 123.123.123.123: bytes=32 time<10ms TTL=128
Reply from 123.123.123.123: bytes=32 time<10ms TTL=128
Reply from 123.123.123.123: bytes=32 time<10ms TTL=128

Ping statistics for 123.123.123.123:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum =  0ms, Average =  0ms 
C:\>ping -a 123.123.123.123

Pinging SQLSERVER1.northamerica.corp.mycompany.com [123.123.123.123] with 32 bytes of data:

Reply from 123.123.123.123: bytes=32 time<10ms TTL=128
Reply from 123.123.123.123: bytes=32 time<10ms TTL=128
Reply from 123.123.123.123: bytes=32 time<10ms TTL=128
Reply from 123.123.123.123: bytes=32 time<10ms TTL=128
Ping statistics for 123.123.123.123:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum =  0ms, Average =  0ms

C:\> 

当命令 ping -a <IPAddress> 解析为运行 SQL Server 的计算机的正确完全限定 DNS 时,客户端解析也会成功。

有关详细诊断,请使用 Test-NetConnection 或 Test-Connection cmdlet 根据计算机上安装的 PowerShell 版本测试 TCP 连接。 有关 PowerShell cmdlet 的更多信息,请参阅 Cmdlet 概述

备注

名称解析方法可能包括 DNS、WINS、主机文件和 Lmhosts 文件。 有关名称解析问题和疑难解答的详细信息,请查看以下链接:

检查目标 SQL Server 的任何别名是否存在于 SQL Server 配置管理器和 SQL Server 客户端网络实用工具中。 如果存在此类别名,请通过检查服务器名称、网络协议、端口号等来确保正确配置它。

步骤 2:验证域之间的通信

验证登录的域是否可以与运行 SQL Server 的服务器的域通信。 域中还必须有正确的名称解析。

  1. 确保可以使用与 SQL Server 服务启动帐户相同的域帐户和密码登录到 Windows。 例如,以下情况可能导致出现 SSPI 错误:

    • 域帐户已锁定。
    • 帐户密码更改后,未重启 SQL Server 服务。
  2. 如果登录域与运行 SQL Server 的服务器的域不同,请检查域之间的信任关系。

  3. 检查服务器所属的域和用于连接的域帐户是否位于同一林中。 SSPI 需要执行此步骤。

步骤 3:使用 SQLCheck 和 Setspn 工具验证 SQL Server SPN

如果可以在本地登录到 SQL Server 计算机并具有管理员访问权限,请使用“Microsoft SQL 网络 GitHub 库”中的 SQLCheck。 SQLCheck 在一个文件中提供了故障排除所需的大部分信息。 有关如何使用该工具及其收集信息的详细信息,请查看该工具的主页。 还可以检查建议的先决条件和清单页。 生成输出文件后,请查看输出文件中 SQL Server 信息 部分下 SQL Server 实例的 SPN 配置。

示例输出:

Suggested SPN                                               Exists  Status              

----------------------------------------------------------  ------  ------------------- 

MSSQLSvc/testsqlsvr.corp.com:2000                           True    Okay                

MSSQLSvc/testsqlsvr.corp.com                                True    Okay                

MSSQLSvc/testsqlsvr:2000                                    False   SPN does not exist. 

MSSQLSvc/testsqlsvr                                         False   SPN does not exist. 

使用上面的输出确定后续步骤 (请参阅下面的示例) 并使用 Setspn 工具采取必要的补救措施来修复 SPN 问题。

应用场景 建议操作
SPN 不存在 为 SQL Server 服务帐户添加所需的 SPN。
重复的 SPN 删除在错误帐户下 SQL 服务已注册的 SPN。
错误帐户下的 SPN 删除错误帐户下 SQL 服务已注册的 SPN,然后在正确的服务帐户下注册 SPN。

备注

  • 可以查看 SQLCheck 工具输出文件中的 SQL Server 信息 部分,查找 SQL Server 实例的服务帐户。

  • Setspn 是 Windows 较新版本中的内置工具,可帮助你读取、添加、修改或删除 Active Directory 中的 SPN。 可以使用此工具验证 SQL Server SPN 是否按照注册 Kerberos 连接的服务主体名称配置。 有关详细信息,请参阅 Setspn 工具和有关如何使用它的示例。

  • 有关 SQL Server 自动注册 SPN 以及需要手动注册 SPN 的情况的详细信息,请参阅注册 Kerberos 连接的服务主体名称

步骤 4:检查链接服务器上 SQL Server 启动帐户的帐户权限

如果在链接服务器的“安全”页上使用“模拟”作为身份验证选项,则需要 SQL Server 才能将传入凭据传递到远程 SQL Server。 定义链接服务器的 SQL Server 启动帐户应具有在 Active Directory 中为其分配的 信任帐户进行委派 的权限。 有关详细信息,请参阅启用要信任委派的计算机和用户帐户

备注

只有在排查与链接服务器查询相关的问题时,才需要执行此步骤。

另请参阅