PC 重启后 SQL Server 2022 连接超时,约 2-5 分钟后恢复
结论
这类问题通常出在某个启动环节尚未就绪,常见情况包括:
- SQL Server 数据库引擎服务尚未完成启动。
- 服务状态已经显示为
Running,但系统数据库或用户数据库仍在恢复。 - 使用命名实例和动态端口时,SQL Server Browser、TCP/IP 或网络尚未就绪。
- 软件启动过早,连接失败后又没有重试。
- 磁盘、杀毒软件、驱动、数据库恢复或 Windows 服务依赖拖慢了启动过程。
客户端连接由数据库引擎处理,普通应用不依赖 SQL Server Agent。启用 Agent 后连接恢复,可能只是启动时序发生了变化,无法据此认定 Agent 是根因。SQL Server Browser 主要用于命名实例、动态端口和实例发现。
先查看 SQL Server 错误日志,确认数据库引擎何时可以接受连接,再根据日志处理服务启动、端口配置或应用重试问题。
确认 SQL Server 服务是否及时启动
默认实例的服务名通常是:
MSSQLSERVER
命名实例的服务名通常是:
MSSQL$实例名
重启后再次出现问题时,以管理员身份打开 PowerShell,并立即执行:
Get-Service MSSQLSERVER, SQLSERVERAGENT, SQLBrowser |
Select-Object Name, Status, StartType
如果使用的是命名实例,例如 SQLEXPRESS,执行:
Get-Service 'MSSQL$SQLEXPRESS', 'SQLAgent$SQLEXPRESS', SQLBrowser |
Select-Object Name, Status, StartType
数据库引擎服务应设为自动启动。可以在 SQL Server Configuration Manager 中修改,也可以使用 PowerShell:
Set-Service -Name MSSQLSERVER -StartupType Automatic
命名实例需要填写实际服务名:
Set-Service -Name 'MSSQL$SQLEXPRESS' -StartupType Automatic
如果服务长时间停留在 StartPending,或者启动后又停止,应先检查 SQL Server 错误日志和 Windows 事件日志。此时调整 Entity Framework 的超时参数无法解决服务本身的启动问题。
查看 SQL Server 错误日志
SQL Server 错误日志是排查这类问题的主要依据。日志目录由实例名和安装路径决定,常见路径如下:
C:\Program Files\Microsoft SQL Server\MSSQL16.MSSQLSERVER\MSSQL\Log\ERRORLOG
命名实例的目录名称会有所不同,不要直接套用这个路径。可以在 SQL Server Configuration Manager 的服务启动参数中查找 -e 参数,它指向当前错误日志。
排查时需要对比这些时间:
- Windows 开机时间
- SQL Server 服务启动时间
- 出现
SQL Server is now ready for client connections的时间 - 各数据库完成恢复的时间
- 软件首次尝试连接的时间
- SSMS 恢复连接的时间
同时搜索以下内容:
Starting up database
Recovery of database
Recovery is complete
SQL Server is now ready for client connections
Error
Failed
I/O requests taking longer
如果从“服务启动”到“可以接受客户端连接”正好间隔 2 至 5 分钟,延迟发生在 SQL Server 初始化或数据库恢复阶段。日志通常会显示正在恢复的数据库、可能存在的 I/O 延迟,以及 tempdb、master 等数据库是否遇到文件访问问题。
连接恢复后,可以通过以下命令读取当前错误日志:
EXEC sys.xp_readerrorlog 0, 1, N'ready for client connections';
EXEC sys.xp_readerrorlog 0, 1, N'Recovery';
EXEC sys.xp_readerrorlog 0, 1, N'Error';
调查前一次启动时,还要检查 ERRORLOG.1 等归档日志。当前服务已经恢复正常,并不能说明故障发生时的状态。
检查 Windows 事件日志
在事件查看器中找到发生故障的启动时段:
Windows 日志 > 应用程序
Windows 日志 > 系统
主要检查以下来源:
MSSQLSERVER或具体 SQL Server 实例- Service Control Manager
- Disk
- Ntfs
- 存储控制器或 SSD 驱动
- Windows Defender 或其他安全软件
查看事件时要按时间顺序梳理启动过程,不能只筛选红色错误。磁盘初始化缓慢、数据库文件被扫描、服务启动超时和驱动重试,都可能导致 SQL Server 在开机几分钟后才能连接。
如果安全软件可能扫描 .mdf、.ndf、.ldf 文件或 SQL Server 日志目录,应按照组织的安全策略评估排除项。未经验证,不要直接关闭防护。
判断 SQL Server Browser 是否有关
SQL Server Browser 帮助客户端查找命名实例使用的 TCP 端口。下面这种连接方式通常需要实例发现:
SERVERNAME\INSTANCE
命名实例使用动态端口时,如果 Browser 尚未启动,客户端可能无法确定连接端口。可以按以下步骤测试:
- 在 SQL Server Configuration Manager 中确认 TCP/IP 已启用。
- 确认实例使用动态端口还是固定端口。
- 临时改用明确的 TCP 地址和端口连接。
- 对比显式端口连接与
服务器名\实例名连接的结果。
假设实例固定监听 1433,可以使用:
Server=tcp:127.0.0.1,1433;Database=AppDb;Integrated Security=True;TrustServerCertificate=True;
如果显式端口可以立即连接,而 计算机名\实例名 需要等待几分钟,可以继续排查 Browser、UDP 1434、名称解析和动态端口发现。
如果显式端口也无法连接,问题通常不在 Browser,应继续检查数据库引擎的启动和恢复过程。
固定端口的具体设置取决于实例部署方案。修改端口后,需要重启 SQL Server 服务,并同步更新防火墙规则和连接字符串。
分别测试不同连接路径
故障发生时,可以使用 sqlcmd 进行短超时测试。实例名和端口需要根据实际环境修改:
sqlcmd -S "localhost" -E -l 5 -Q "SELECT @@SERVERNAME"
sqlcmd -S "tcp:127.0.0.1,1433" -E -l 5 -Q "SELECT @@SERVERNAME"
sqlcmd -S "localhost\SQLEXPRESS" -E -l 5 -Q "SELECT @@SERVERNAME"
sqlcmd -S "lpc:localhost" -E -l 5 -Q "SELECT @@SERVERNAME"
可以根据测试结果缩小排查范围:
- 本地共享内存连接成功,但 TCP 失败:检查 TCP/IP、监听端口、防火墙和网络初始化。
- 显式 TCP 端口成功,但命名实例失败:检查 Browser 和实例发现。
- 所有连接方式都失败:数据库引擎可能尚未就绪,服务可能发生异常,或者数据库恢复受阻。
sqlcmd成功但应用失败:检查应用连接字符串、凭据、启动账户和连接重试逻辑。
机器上不一定已经安装 sqlcmd。如果没有,也可以使用 SSMS 分别测试 localhost、显式 TCP 端口和命名实例。
不要让软件在用户登录后立即启动
开机启动程序可能早于数据库服务。Windows 已经显示桌面时,SQL Server 仍可能处于数据库恢复阶段。
如果通过任务计划程序启动软件,可以采用以下设置:
- 登录后延迟几十秒启动。
- 等目标服务运行后再启动。
- 启动失败后按一定间隔重新运行。
- 使用具备正确权限的 Windows 账户。
服务状态显示为 Running 时,目标数据库仍可能尚未进入 ONLINE 状态。因此,应用最好先执行一次短连接探测,成功后再继续初始化。
连接成功后,可以查询数据库状态:
SELECT name, state_desc
FROM sys.databases
ORDER BY name;
目标数据库应处于 ONLINE 状态。如果它长时间停留在 RECOVERING、RECOVERY_PENDING 或 SUSPECT,需要根据错误日志处理数据库恢复问题。
在应用中加入有限重试
开机时服务短暂不可用并不罕见。应用不应因为第一次连接超时而一直停留在失败状态。可以设置有限次数的重试,逐步增加等待间隔,并记录每次异常。
EF Core 使用 SQL Server 提供程序时,可以启用连接重试:
services.AddDbContext<AppDbContext>(options =>
{
options.UseSqlServer(
connectionString,
sqlOptions =>
{
sqlOptions.EnableRetryOnFailure(
maxRetryCount: 8,
maxRetryDelay: TimeSpan.FromSeconds(15),
errorNumbersToAdd: null);
});
});
如果连接发生在依赖注入容器创建之前,或者程序启动时需要执行迁移、初始化数据,还要在外围增加启动探测。例如:
using Microsoft.Data.SqlClient;
static async Task WaitForDatabaseAsync(
string connectionString,
CancellationToken cancellationToken)
{
const int maxAttempts = 12;
for (var attempt = 1; attempt <= maxAttempts; attempt++)
{
try
{
await using var connection = new SqlConnection(connectionString);
await connection.OpenAsync(cancellationToken);
await using var command = connection.CreateCommand();
command.CommandText = "SELECT 1";
command.CommandTimeout = 5;
await command.ExecuteScalarAsync(cancellationToken);
return;
}
catch (SqlException) when (attempt < maxAttempts)
{
var delay = TimeSpan.FromSeconds(Math.Min(attempt * 5, 30));
await Task.Delay(delay, cancellationToken);
}
}
throw new InvalidOperationException(
"SQL Server did not become available within the startup retry period.");
}
生产环境还应记录 SqlException.Number、发生时间、服务器地址和重试次数,但不要记录密码或完整的敏感连接字符串。
如果只是把连接字符串中的 Connect Timeout 增加到几分钟,程序会长时间卡在单次连接上,也不便于诊断。短超时加有限重试通常更容易观察问题,也更容易恢复。
检查其他启动因素
如果错误日志显示 SQL Server 本身启动较慢,还需要检查:
- 数据库文件和日志文件是否位于可用的本地磁盘。
- 是否有数据库在每次启动时都要执行较长时间的崩溃恢复。
- SQL Server 服务账户能否及时访问数据库目录。
tempdb文件路径是否存在,权限是否正确。- 系统盘或数据库盘在启动时是否出现高延迟。
- Windows Defender、第三方杀毒软件或备份软件是否正在扫描数据库文件。
- SQL Server 是否安装了适用于当前系统的更新。
- 操作系统、芯片组、存储控制器和 SSD 固件是否正常。
较高的硬件规格无法排除启动阶段的 I/O、驱动或文件扫描问题。仍需根据错误日志、事件日志和可复现的时间线判断原因。
排查顺序
- 复现故障并记下准确时间。
- 检查数据库引擎服务状态,暂时不用关注 SQL Server Agent。
- 查看
ERRORLOG,确认从“服务启动”到“可接受连接”是否间隔了数分钟。 - 分别测试共享内存、显式 TCP 端口和命名实例。
- 检查 Windows 应用程序日志和系统日志。
- 如果只有实例发现失败,检查 Browser、动态端口和名称解析。
- 如果数据库引擎恢复缓慢,排查数据库恢复、磁盘、驱动和安全软件。
- 为开机启动的软件设置延迟、健康检查和有限重试。
没有日志证据时,不要把自动启动 SQL Server Agent 或 Browser 当作通用修复方案。应先判断故障发生在数据库引擎启动、数据库恢复、网络协议还是实例发现阶段,再处理对应环节。
备注:内容仅供参考。
