遇到 SQL Server 登录报 18456,我估计每一位 DBA 和做后端开发的同事都经历过几个不眠之夜。你可能会看到两种完全不同的现象:一种是客户端直接弹一个“用户 ‘sa’ 登录失败”,另一种是错误日志里一大段文字,看得人头大。其实 18456 这个错误码本身只是一个“壳子”,真正决定问题方向的是它后面跟着的状态码。只要会读状态码,80% 的登录问题都能在几分钟内定位,剩下的就是按方子抓药的事。
这篇文章我会把 18456 错误的来龙去脉讲透,包括状态码怎么读、错误日志去哪里翻、每种状态码背后的修复步骤,以及我这些年实际踩过的坑。不管你是刚接手 SQL Server 的新手运维,还是被测试环境折腾到怀疑人生的开发同学,只要你手里有能登录操作系统的权限,照着下面的方法一步步来,基本都能解决。
1. 先搞清楚报错“身份”:状态码和错误日志怎么读
1.1 为什么都是18456,原因可能完全不一样
很多人在搜索引擎里输入“SQL Server 18456”,然后照着网上说的“启用混合身份验证模式”“重置 sa 密码”试了一圈,结果问题没解决。原因很简单:18456 只是一个总错误号,就像医院里的“发热门诊”,引起发热的原因可能是感冒、可能是肺炎、也可能是其他问题,你得先分诊。
SQL Server 真正告诉我们“病因”的,是错误消息里打印出来的状态码。我整理了一份日常最高频的状态码对照表,建议你收藏起来:
| 状态码 | 含义 | 最常见的场景 |
|---|---|---|
| 1 | 错误信息本身的问题,或信息不足 | 极少见,先看完整错误日志 |
| 2 | 无效的用户标识 | 登录名不存在,或连接串写错了登录名 |
| 5 | 无效的用户标识或密码 | 密码错误、账号不存在、认证模式不匹配 |
| 6 | 尝试使用已禁用的登录名 | sa 被禁用,或新建的 SQL 登录名是禁用状态 |
| 7 | 登录名已锁定 | 连续输错密码,触发了账户锁定策略 |
| 8 | 密码已过期 | 开启了密码过期策略 |
| 9 | 密码必须更改 | 强制修改密码后尚未修改 |
| 11 | 有效登录,但服务器访问失败 | 登录名没有 CONNECT 权限,或服务器处于特殊状态 |
| 12 | 登录名被映射到了禁用的凭据 | 证书/对称密钥映射类问题 |
| 18 | 密码必须更改,请求不被允许 | 密码策略与账户状态冲突 |
这里要注意,你从 SSMS 图形界面上看到的“错误: 18456”并不带状态码,真正带状态码的是 SQL Server 错误日志和 Windows 事件日志中的原文。所以第一步不是去乱改配置,而是先打开错误日志,把里面那行带状态码的记录捞出来。
1.2 三分钟找到SQL Server错误日志的原文
SQL Server 错误日志的默认位置一般在安装目录的 Log 文件夹下,比如 SQL Server 2019 默认实例的路径是:
C:\Program Files\Microsoft SQL Server\MSSQL15.MSSQLSERVER\MSSQL\Log\ERRORLOG注意实例名不同,中间的目录名也会不一样。MSSQL15 对应 2019,MSSQL14 对应 2017,MSSQL16 对应 2022。如果你不确定路径,最简单的办法是在 SSMS 里连接上服务器(哪怕用 Windows 身份),在“管理→SQL Server 日志”里直接查看当前日志。但很多时候我们就是登录不上才来排查,所以直接用记事本打开 ERRORLOG 文件更靠谱。
打开文件后,拉到最底部,找包含 “Login failed” 的行。一个典型的登录失败记录长这样:
2025-01-06 23:15:31.01 Logon 错误: 18456,严重性: 14,状态: 5。 2025-01-06 23:15:31.01 Logon 登录失败。原因: 为所提供的登录名提供的密码不匹配。[客户端: 192.168.1.101]看到状态: 5和密码不匹配,就可以放心往密码和认证模式方向去查了。再比如:
错误: 18456,严重性: 14,状态: 6。 登录失败。原因: 尝试使用禁用的登录名。 [客户端: 192.168.1.101]这就是典型的状态 6,登录名被禁用了。
补充一个关键点:错误日志里的 [客户端: xxx] 表示连接的来源 IP,如果显示的是本地 IP 或者 127.0.0.1,说明请求是本机发出的。这能帮我们判断是客户端连不上,还是服务端在拒绝认证。
2. 动手改配置前,先做好这些基础检查
2.1 服务真的在监听吗?端口和协议排查
有一次帮朋友看问题,他折腾了半天 sa 密码,最后我发现数据库服务压根没起来。所以在看认证之前,先确认三件事:服务是否在运行、网络协议是否启用、端口是否正常监听。
先打开 Windows 服务管理器(services.msc),找到以 SQL Server (实例名) 开头的服务,确认状态是“正在运行”。如果服务没起来,后面的所有排查都白搭。服务正常之后,打开 SQL Server 配置管理器,展开“SQL Server 网络配置”,找到对应实例的协议,确认 TCP/IP 是“已启用”状态。SQL Server 默认安装时,TCP/IP 协议有时是禁用状态,尤其是仅安装了数据库引擎、没做网络配置的机器,本地能用 Windows 身份连,远程一律 18456。
TCP/IP 启用后,还需要确认端口。默认实例一般监听 1433,命名实例默认动态端口。在配置管理器的“TCP/IP 属性→IP 地址→IPAll”里,可以找到 TCP 动态端口和 TCP 端口。如果要固定端口,就把“TCP 动态端口”里的值清空,在“TCP 端口”里填 1433,然后重启 SQL Server 服务。
验证端口是否真的在监听,用命令:
netstat -ano | findstr 1433如果看到LISTENING状态,说明端口没问题。没看到的话,要么 TCP/IP 协议没启用,要么服务没起来,要么端口被改了。这时候再去翻协议设置。
还要提一嘴 SQL Server Browser 服务。如果你用的是命名实例(比如计算机名\SQLEXPRESS),客户端需要通过 Browser 服务的 UDP 1434 端口获得实例的端口号。这个服务默认可能是“手动”或“已停止”,连不上时记得确认它已经启动。
2.2 身份验证模式到底选的哪个?
这是 18456 里最常被忽略的一个原因。SQL Server 安装默认是“Windows 身份验证模式”。在这种模式下,你用 sa 或其他 SQL 账号登录,不管密码敲得多正确,服务端都直接拒绝,错误日志里的状态码通常是 5,但真实原因并不是密码错了,而是服务端根本不认 SQL 登录这种认证方式。
查看当前认证模式,可以用 SSMS 登录后右键服务器属性,在“安全性”页签里看“服务器身份验证”。如果是“Windows 身份验证模式”,那就说明问题出在这里。
改成混合模式的操作路径:SSMS → 右键服务器 → 属性 → 安全性 → 选“SQL Server 和 Windows 身份验证模式” → 确定。改完之后,必须重启 SQL Server 服务才能生效。这一步千万别忘,我见过有人改完不重启,然后继续怀疑人生。
如果你不方便用图形界面,注册表也可以改。SQL Server 的认证模式存在这里:
HKLM\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL15.MSSQLSERVER\MSSQLServer\LoginModeLoginMode 的值是 1 表示仅 Windows 认证,2 表示混合认证。改成 2 后同样要重启服务。
2.3 连接的账号本身状态完整吗?
认证模式没问题之后,就该看登录名本身了。SQL Server 里一个 SQL 登录名有几项属性会直接导致 18456:
- 禁用状态(is_disabled)
- 密码是否过期(is_expiration_checked)
- 是否被锁定(LOGINPROPERTY 查询)
- 是否被强制修改密码(IsMustChange)
用 Windows 身份先连上数据库,执行下面这条 SQL,就能把用户的状态一次性看明白:
SELECT name, is_disabled, is_policy_checked, is_expiration_checked, LOGINPROPERTY(name, N'IsLocked') AS is_locked, LOGINPROPERTY(name, N'IsMustChange') AS must_change_password FROM sys.sql_logins WHERE name = N'sa';网上很多教程直接告诉你“用 ALTER LOGIN sa WITH PASSWORD ‘xxx’ 重设密码”,但忽略了用户是否禁用、是否被锁。如果 is_disabled 是 1,光改密码是没用的,还得显式执行一次启用操作。后面我会把每条状态码对应的处理步骤单独列出来,你照着做就行。
3. 按状态码对症下药:把每种“死法”都救活
3.1 状态5或状态2:账号或密码不对,可背后还有5种情况
状态 5 是出现频率最高的一种,错误日志原文通常写着“密码不匹配”或者“为所提供的登录名提供的密码不匹配”。但我在实际排查中发现,状态 5 背后往往藏着好几种不同的根因:
- 密码确实输错了。
- 登录名写错了,比如把
sa写成了admin,或者连接串里账号带了多余的空格。 - 服务器认证模式是仅 Windows,SQL 登录被直接拒绝。
- 客户端和服务端之间加密 TLS 设置不匹配,导致认证握手失败。
- 密码里的特殊字符没有正确转义。
前两种好办,重新确认账号密码就行。第三种按上一节改成混合认证并重启。第四种在较新的 SQL Server 版本里容易遇到,特别是客户端用了新版驱动时默认启用了强制加密,而服务端没有配置证书。这时候错误可能表现为状态 5,但错误日志里往往还有一条关于证书或 SSL 的记录。可以先在连接字符串里加TrustServerCertificate=True,或者把驱动的 Encrypt 改成 Optional 再试。
第五种常见于在应用配置文件里写连接串时,密码包含;、'、"之类字符。比如:
Server=192.168.1.10;User Id=sa;Password=abc;123分号会把连接字符串截断,导致密码解析成abc,自然就报密码不匹配。解决办法是把密码单独放到配置项,或者用 .NET 的 SqlConnectionStringBuilder 来拼接。
真正的“忘记 sa 密码”情况,只要你有 Windows 管理员权限,还是能救回来的。以管理员身份打开命令提示符,把 SQL Server 服务以单用户模式拉起来,然后重置 sa 密码。操作步骤我会在第 4 节里完整展开。
3.2 状态6、状态7、状态8、状态9:禁用、锁定、密码过期,一套命令全搞定
这几个状态码放在一起说,因为它们的处理逻辑是相通的,都是“账号本身活着,但状态不让用”。
状态 6 表示登录名被禁用。常见于安装后从未启用过 sa,或者 DBA 出于安全考虑禁用了某个应用账号。修复命令:
ALTER LOGIN [sa] WITH PASSWORD = N'新密码', CHECK_POLICY = OFF; ALTER LOGIN [sa] ENABLE;如果不想改密码,只想启用:
ALTER LOGIN [sa] ENABLE;状态 7 是账户被锁定。SQL Server 的密码策略里如果开启了“账户锁定阈值”,连续多次失败登录后账户会被锁。查询锁定状态用上面提到过的 LOGINPROPERTY,解锁命令:
ALTER LOGIN [sa] WITH UNLOCK;解锁后建议顺手确认一下密码策略配置是否合理。如果业务上确实存在暴力破解风险,阈值可以保留,但别设得太小,否则一个手滑的脚本就能把生产账号锁干净。
状态 8 是密码过期,状态 9 是必须更改密码。这俩通常出现在开启了密码过期策略的数据库上,或者管理员在创建登录名时勾选了“强制密码过期”。修复方式就是改密码:
ALTER LOGIN [sa] WITH PASSWORD = N'新密码';如果密码策略限制太死,你可以像上面那样在修改时加CHECK_POLICY = OFF和CHECK_EXPIRATION = OFF,但生产环境我不建议这么做,密码策略的初衷是安全,不是给我们添堵的。
3.3 状态11或状态12:登录名没问题,但没进门的资格
状态 11 很多人不熟。这个状态的意思是:服务端已经验证了你的账号密码,也认可你是合法登录名,但因为某些原因不让你进门。
最常见的情况是登录名缺少CONNECT SQL权限。SQL Server 里每个登录名必须拥有连接数据库引擎的权限,默认情况下 sysadmin 角色和 public 角色可以连接。如果某个登录名被显式拒绝,或者服务器角色被改得比较迷,就会看到状态 11。修复方式是在“登录名属性→安全对象”里授予“连接 SQL”权限,或者用脚本:
GRANT CONNECT SQL TO [你的登录名];还有一种特殊情况:SQL Server 启动时加了-m单用户参数。单用户模式下系统只允许一个连接,其他连接请求会以状态 11 被拒绝。如果确认服务器处于单用户模式(可以通过 SQL Server 配置管理器查看启动参数),等维护结束把-m参数去掉并重启服务即可。
状态 12 相对少见,它和证书、对称密钥映射有关。如果你不是在做“凭据映射”相关的高级配置,基本不用担心这个状态码。真遇到了,先回顾最近有没有做过证书切换或恢复,然后检查对应证书的有效期。
3.4 其他少见状态码:遇到也别慌
状态 1、状态 2、状态 40、状态 46 这些属于低频状态码。状态 1 常常伴随着错误日志本身不完整,优先去 Windows 事件查看器里捞更多细节。状态 40 和 46 疑似和 TLS 加密协商相关,建议检查 SQL Server 的 TLS 配置、客户端驱动版本以及是否安装了最新的累积更新。总原则是:先看完整日志原文,再看服务端和客户端两端的通信协议,不要盲目改密码。
4. 从报错到修复:一次典型故障排查实录
4.1 故障现象:SQL客户端爆出18456,Windows认证却正常
之前有朋友的公司内部系统突然连不上测试库,SQL Server 的 sa 登录报 18456,但用 Windows 身份认证却能顺利连上。一开始他以为是 sa 密码被人改了,找我帮忙。我先在本地用 Windows 身份连上数据库,执行了认证模式查询,发现服务器身份验证确实是混合模式,密码对不上这一条就被排除了大部分。
接着我打开错误日志,看到里面的记录是:
错误: 18456,严重性: 14,状态: 5。 登录失败。原因: 为所提供的登录名提供的密码不匹配。但蹊跷的是,这个报错记录对应的客户端 IP 是测试机本身的 IP,也就是说有人在测试机上用 sa 登录,但密码不匹配。我让他自己在测试机上用 sqlcmd 再试一次,并确认输入的密码和运维手里记录的密码是否完全一致。
4.2 排查步骤的递进思路:从日志一行开始定位
后来发现,问题就出在运维那边保存密码时多了一个空格。这个事听起来很蠢,但确实发生过很多次——密码在 Excel、备忘录、邮件转发过程中被自动加了个空格,复制到配置文件里完全看不出来。用 sqlcmd 手动输入密码后,连接成功。
这里我想强调的是排查思路的递进:看到 18456,先不急着改密码,第一件事永远是看日志里的状态码和原因描述;第二件事是确认认证模式;第三件事才是验证账号密码。顺序反了,很容易做出“无效修改”,甚至把原本正常的配置搞坏。
在这个案例里,如果一开始就按网上说的“重置 sa 密码”操作,虽然也能解决问题,但会造成一次不必要的密码变更,所有依赖 sa 的应用都得跟着改。而从日志和认证模式入手,只花了五分钟就定位到是“密码复制多了空格”。
4.3 如果手里只剩sa密码,又没有Windows管理员怎么办
这是最麻烦的场景,但也不是完全没有办法。如果操作系统管理员权限也没了,那就比较棘手,因为 SQL Server 的恢复逻辑依赖 Windows 权限。这里我假设你至少还有 Windows 管理员权限,只是 sa 密码彻底失传。
以管理员身份打开命令提示符,先把 SQL Server 服务停掉:
net stop MSSQLSERVER然后以单用户模式启动:
net start MSSQLSERVER -m注意,-m参数会限制为单用户连接,且默认只允许本地连接。启动完成后,另开一个命令提示符,用 Windows 身份连接:
sqlcmd -S . -E连接成功后,在 sqlcmd 里重置 sa 密码:
ALTER LOGIN [sa] WITH PASSWORD = N'你的新密码', CHECK_POLICY = OFF; ALTER LOGIN [sa] ENABLE; GO执行完GO后退出 sqlcmd,然后重启服务,这次不要带-m参数:
net stop MSSQLSERVER net start MSSQLSERVER最后用新密码连接验证。需要提醒的是,单用户模式下如果连接不释放,其他连接是进不来的。如果你在 sqlcmd 窗口挂太久,记得及时退出。我在实际操作中习惯执行完脚本立刻exit,避免占用连接导致自己把自己锁在门外。
4.4 如果Windows身份也登不上:旧账重提的恢复方案
如果你连 Windows 身份都连不上,一种可能是当前 Windows 用户不在任何 sysadmin 角色的成员列表里。这种情况只能通过单用户模式 + 管理员操作系统权限恢复,思路和上面一样,但是登录时要用-E选项。SQL Server 在单用户模式下会允许本地 Windows 管理员作为 sysadmin 登录,这也是微软留下的后门通道。恢复后第一时间把当前 Windows 用户加到 sysadmin 服务器角色,然后重新启动正常模式。
这一步的操作意图很明确:在没有任何可用 SQL 登录名的情况下,借助操作系统的管理员身份强制进入实例,重置 sa 密码或修复合法的管理员登录名。整个过程要小心别在生产库上执行错了命令,最好先在测试环境演练一遍。
5. SQL Server登录失败排查速查表与避坑指南
5.1 五分钟快速判断问题域的思路
遇到 18456 不用慌,按照下面这个三步法走:
- 看状态码:从 SQL Server 错误日志或 Windows 事件日志里找到 18456 对应的状态码。
- 看日志原文:找到“原因”后面的描述,比如“密码不匹配”“禁用”“锁定”。
- 对表定位:结合状态码和描述,确定是认证模式类、账号状态类还是权限类问题。
只要状态码读对了,至少能节约半小时的盲目排错时间。我在处理其他同事提交的问题时,通常让同事先截图错误日志原文,配合状态码基本能直接给出处理方向。
5.2 常见问题速查表
| 现象 | 状态码 | 可能原因 | 处理建议 |
|---|---|---|---|
| sa 登录报 18456,原因“密码不匹配” | 5 | 密码错误 / 认证模式不匹配 / 密码含特殊字符 | 确认密码,检查认证模式,检查连接串转义 |
| sa 登录报“禁用的登录名” | 6 | sa 或登录名被禁用 | ALTER LOGIN [sa] ENABLE |
| 连续输错密码后被锁 | 7 | 触发账户锁定策略 | ALTER LOGIN [sa] WITH UNLOCK |
| 登录报“密码已过期” | 8 | 密码策略过期 | 修改密码 |
| 登录报“密码必须更改” | 9 | 强制密码修改 | 修改密码,或调整密码策略 |
| 本地 Windows 能连,远程 18456 | 5/11 | TCP/IP 未启用 / 防火墙未放行 / 端口没监听 | 启用 TCP/IP,固定端口,放行防火墙 |
| 应用连不上,报 18456,日志有 SSL 相关 | 5 | TLS 配置不匹配 | 连接串加 TrustServerCertificate=True |
| SQL 登录被拒绝 | 11 | 缺少 CONNECT SQL 权限 | GRANT CONNECT SQL TO 登录名 |
这张表只覆盖了高频场景。如果你想把它变成自己的排查武器,建议把表里的状态码和原因描述抄到自己的笔记里,下次报错时对照着看,效率翻倍。
5.3 新手最容易踩的5个坑
第一,改完认证模式不重启服务。很多人在 SSMS 里切换成混合模式后直接测试,发现还是 18456,然后怀疑自己操作错了。实际上认证模式的改动必须重启 SQL Server 服务才生效。
第二,启用 TCP/IP 后不重启服务或不停在配置里固定端口。TCP/IP 协议启用后同样需要重启服务,动态端口如果不固定,客户端下次连接可能找不到入口。
第三,密码重置后不检查“禁用”状态。sa 或某个 SQL 登录名在重置密码后仍然是禁用状态,你以为是密码问题,实际是禁用问题。
第四,防火墙只开了 1433 端口,却忽略了命名实例需要 UDP 1434。如果你连的是命名实例,只开 1433 不够,SQL Server Browser 服务的 UDP 1434 也要放行。
第五,把生产库的密码策略直接关掉。有些同学图省事,修改 sa 密码时把所有策略都关掉,结果生产环境的安全审计被打穿。我的建议是:即使要临时关闭,事后也要恢复合理的密码策略。
5.4 我的两个独家小技巧
技巧一:在测试环境里故意制造一次 18456 错误,然后去错误日志里找对应记录。这个方法对新手特别管用,你可以亲手感受一下“状态码 5”和“状态码 6”在日志原文中的区别。一旦你见过真实的日志格式,以后再遇到就不会慌。
技巧二:使用 sqlcmd 命令验证连接时,加上-l参数控制登录超时,避免因为网络问题一直卡在那里。一个标准的测试命令是:
sqlcmd -S 192.168.1.10 -U sa -P '你的密码' -l 5如果本地 sqlcmd 测试通过,但程序连接失败,问题基本出在连接串或驱动的配置上。如果本地测试也失败,那就老老实实按状态码去排查服务端。
我之前处理过一个最复杂的案例,本地 sqlcmd 能连、本机程序也能连,偏偏远程程序连不上。后来查出来是服务器上配置了多个 IP,SQL Server 监听的是其中一个内网 IP,而客户端访问的是另一个 IP。这种问题排查到最后已经不是 18456 本身能解决的了,需要结合网络拓扑和 SQL Server 监听地址一起看。遇到这种概率很低的配置问题时,别钻牛角尖,先检查服务监听地址是否与客户端访问地址一致。
最后再分享一点个人体会:SQL Server 的 18456 错误是数据库维护工作中最常见的登录类错误之一,但它从来不是“玄学”。它的背后永远是具体的配置状态、账号状态、网络状态和权限状态。读日志、看状态码、按步骤排查,这套流程走完,绝大多数问题都能迎刃而解。希望这篇内容能帮你少走几步弯路,尤其是在那些让人容易忽视的细节上。