客户端连SQL Server,弹出一个框:用户 'sa' 登录失败。(Microsoft SQL Server,错误: 18456)。后面还跟着严重性14、状态1。这个状态1什么都说明不了,它是故意给客户端看的占位值,真正的原因被藏在服务器端的错误日志里。
很多人在这一步就开始猜密码对不对、账号是不是锁了,来回折腾。其实18456的排查有个固定入口:先看服务端日志里的状态号,再按号查表。
状态号要去哪里看
SQL Server错误日志(ERRORLOG)默认在实例安装目录下,路径形如C:\Program Files\Microsoft SQL Server\MSSQL16.MSSQLSERVER\MSSQL\Log\ERRORLOG,中间那截MSSQL16对应版本号,MSSQL15是2019、MSSQL16是2022、MSSQL17是2025。也可以在SSMS里展开管理、SQL Server日志,双击当前那条直接看。
日志很长,用系统存储过程过滤更快:
EXEC xp_readerrorlog 0, 1, N'18456', NULL, NULL, NULL, N'desc';
第二个参数1表示查SQL Server错误日志(填2是代理日志),0表示当前这个ERRORLOG文件。日志循环切换过的要往前翻,把0改成1、2、3依次试。
还有个更快的办法,直接从内存里的安全错误环形缓冲区取:
SELECT CAST(record AS XML) AS err FROM sys.dm_os_ring_buffers WHERE ring_buffer_type = N'RING_BUFFER_SECURITY_ERROR';
这个缓冲区重启就清空,查历史还是得靠ERRORLOG。
日志里的记录长这样,[CLIENT: 后面是来源IP,State那一位才是关键:
Login failed for user 'sa'. Reason: Password did not match that for the login provided. [CLIENT: 10.0.0.7]
状态号对照
把日志里的State值跟下面这张表对一下,方向立刻就清楚了。
状态2和5:用户ID无效,也就是这个登录名在实例上根本不存在。域账号要写成DOMAIN\user,连接字符串里那个反斜杠在部分语言里得写成两个。
状态6:拿Windows登录名去做SQL Server身份验证了,认证方式选错。
状态7:登录被禁用,同时密码也不对。状态8:密码不正确。状态9:密码无效。这三个里8最常见,见过一台对公网开放的实例,ERRORLOG一天几千条状态8,全是扫sa的。
状态11和12:登录本身是有效的,但服务器访问失败。这一档最容易被误判。常见情形是Windows账号靠本地管理员组的成员身份连进SQL Server,可Windows没把管理员凭据给出去,解决办法是用以管理员身份运行启动客户端,或者把这个Windows账号显式建成登录名。
状态18:密码必须更改,登录被标了MUST_CHANGE且已过期。
状态38和46:找不到用户请求的数据库。状态126:请求的数据库不存在。这两档看着像数据库没了,实际多半是这个登录的默认数据库被删掉、脱机、处于单用户或正在还原状态,连接一开始就撞上去。改掉默认库即可:
ALTER LOGIN [appuser] WITH DEFAULT_DATABASE = master;
状态58:服务器只开了Windows身份验证,客户端却用SQL账号登录。改认证模式要到SSMS里右键实例、属性、安全性,选SQL Server和Windows身份验证模式,确定之后必须重启SQL Server服务才生效,这一步漏了就会一直报。
状态62:包含数据库里SID不匹配,库是拷过来的、登录是重建的,两边对不上。
状态122到124:用户名或密码为空,连接串拼错、配置文件里的键名写错都会走到这里。状态102到111是Azure AD相关。
改完之后怎么验证
sa账号被禁用的情况很常见,启用并改密码一次做完:
ALTER LOGIN sa ENABLE; ALTER LOGIN sa WITH PASSWORD = '新密码';
密码策略CHECK_POLICY开着的话,简单密码会被拒,报的是15116而不是18456,别看混了。想临时绕开就加CHECK_POLICY = OFF,生产环境不建议。
验证连接别只依赖SSMS的对话框,用sqlcmd直接指定协议和端口,能把网络层和认证层分开:
sqlcmd -S tcp:192.168.1.10,1433 -U appuser -P 密码 -d master -C
连不上先看是不是压根没到认证这一步。命名实例用的是动态端口,得开SQL Server Browser服务(UDP 1434),或者直接给实例固定一个TCP端口并在连接串里写明。固定端口在SQL Server配置管理器里的网络配置、TCP/IP属性、IP Addresses页签,改完一样要重启服务。
之前遇到过一次,报18456但状态一直是1,原因是ERRORLOG里根本没有对应记录,说明请求压根没打到引擎上,实际是防火墙把1433挡了。这个判断方法很省事:日志里查不到,就别在认证上耗时间,直接去查网络。
几个容易混的相邻报错
4064是登录成功但打不开默认数据库,跟状态38、46同源但出现在客户端;17806是SSPI握手失败,Kerberos那边SPN没注册对,域环境里远程连不上基本都是它;18452是无法连接到服务器,常出现在跨信任域的场景;53是找不到网络路径,纯网络层问题。
想长期盯着失败登录,可以在实例属性的安全性页把登录审核改成失败和成功的登录,或者建一条SQL Server Audit,再用sys.fn_get_audit_file去查。默认配置只记失败登录,成功的不写。
数据截至2026年10月,SQL Server 15.0、16.0、17.0,三代在支持期内的版本号,17.0对应2025年11月18日发布的SQL Server 2025;2026年9月的补丁分别是15.0.2190.7、16.0.1200.5、17.0.1135.8。日志里的状态号含义在各版本间保持一致。