PAYATHON 2026

PC 重启后 SQL Server 2022 连接超时,约 2-5 分钟后恢复

排障赵师傅

结论

这类问题通常出在某个启动环节尚未就绪,常见情况包括:

  1. SQL Server 数据库引擎服务尚未完成启动。
  2. 服务状态已经显示为 Running,但系统数据库或用户数据库仍在恢复。
  3. 使用命名实例和动态端口时,SQL Server Browser、TCP/IP 或网络尚未就绪。
  4. 软件启动过早,连接失败后又没有重试。
  5. 磁盘、杀毒软件、驱动、数据库恢复或 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 尚未启动,客户端可能无法确定连接端口。可以按以下步骤测试:

  1. 在 SQL Server Configuration Manager 中确认 TCP/IP 已启用。
  2. 确认实例使用动态端口还是固定端口。
  3. 临时改用明确的 TCP 地址和端口连接。
  4. 对比显式端口连接与 服务器名\实例名 连接的结果。

假设实例固定监听 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、驱动或文件扫描问题。仍需根据错误日志、事件日志和可复现的时间线判断原因。

排查顺序

  1. 复现故障并记下准确时间。
  2. 检查数据库引擎服务状态,暂时不用关注 SQL Server Agent。
  3. 查看 ERRORLOG,确认从“服务启动”到“可接受连接”是否间隔了数分钟。
  4. 分别测试共享内存、显式 TCP 端口和命名实例。
  5. 检查 Windows 应用程序日志和系统日志。
  6. 如果只有实例发现失败,检查 Browser、动态端口和名称解析。
  7. 如果数据库引擎恢复缓慢,排查数据库恢复、磁盘、驱动和安全软件。
  8. 为开机启动的软件设置延迟、健康检查和有限重试。

没有日志证据时,不要把自动启动 SQL Server Agent 或 Browser 当作通用修复方案。应先判断故障发生在数据库引擎启动、数据库恢复、网络协议还是实例发现阶段,再处理对应环节。

备注:内容仅供参考。