Windows服务启动报错1053与1067的排查方法(服务没有及时响应启动或控制请求与进程意外终止的定位)

在services.msc里点启动,弹窗报「错误1053:服务没有及时响应启动或控制请求」,或者报「错误1067:进程意外终止」。命令行里net start的表现是停在「服务正在启动...」,然后甩一句「服务无法启动」,别的什么都不给。这两个报错看着像一回事,其实是两条完全不同的路,先分清是哪个再动手,能省掉一堆无用功。


1053与1067的分界

1053是超时。服务控制管理器(SCM)给一段固定时间,进程必须在这段时间内回报「已运行」,没回报就被判定为启动失败,默认这个值是30000毫秒。程序本身可能是好的,只是启动时要连一次远程数据库、要读几十兆的配置、要做一次全量同步,慢了就被砍掉。

1067是进程起来了又自己退出,退出码不是0。这种通常跟环境有关:配置文件读不到、依赖的动态库缺失、账户没有权限、工作目录不对。

区分两者最快的办法是看系统日志里的事件ID。7009和7011对应超时,7000是启动失败,7034和7031是进程意外终止,7038是登录身份不对。看到7009就去查启动耗时,看到7034就去查程序为什么退出。


把系统日志里的原始记录翻出来

图形界面走eventvwr.msc,展开Windows日志下面的系统,按来源Service Control Manager筛选。一次要看很多条的时候,命令行更快:

wevtutil qe System /q:"*[System[Provider[@Name='Service Control Manager'] and (EventID=7000 or EventID=7009 or EventID=7011 or EventID=7034 or EventID=7038)]]" /f:text /c:30

习惯用PowerShell的话,取最近一天的记录:

Get-WinEvent -FilterHashtable @{LogName='System';ProviderName='Service Control Manager';Id=7000,7009,7011,7031,7034,7038;StartTime=(Get-Date).AddDays(-1)} | Select-Object TimeCreated,Id,Message

之前碰到过一台机器弹窗报1053,事件里却没有7009,翻出7038才发现服务账号的域密码上周改过,而服务配置里的旧密码一直没更新。报错码和真实原因对不上是常事,别只盯着弹窗那句话。


手动把程序跑一遍

1067这一类,最有效的定位手段是绕开服务控制管理器,直接执行那个可执行文件。

这个坑踩过不止一次。

先把服务对应的命令行查出来:

sc qc MyService

输出里的BINARY_PATH_NAME就是真实命令,参数一起抄下来。接着cd到那个目录,把命令原样跑一遍。

服务的当前工作目录是C:\Windows\System32,不是程序所在的目录。程序里写了「./config.yaml」这种相对路径,双击运行时好好的,装成服务就找不到文件,进程启动即退出,弹窗只会报1067。实测过的处理办法有两种:改程序用绝对路径,或者给服务配一个工作目录(用NSSM 2.24这类工具托管时能直接设AppDirectory)。

控制台程序直接跑的时候,OnStart里抛的异常会打在屏幕上;装成服务之后这层异常被吞掉,只剩下「进程意外终止」一句。所以手动跑一遍几乎是1067的必做项。


服务账户与登录身份

事件7038的意思是服务无法以配置的身份登录。常见三种:域账号密码改了没同步、账号被禁用、账号没有「作为服务登录」的权利。

前两种在services.msc属性页的登录标签里重新填一次密码就能验证。第三种要去secpol.msc,本地策略下的用户权利指派里找「作为服务登录」,把账号加进去。域环境下这条通常由组策略下发,本地改了也可能被覆盖回去。

还有一类:服务用Local System跑没问题,换成普通账号就报1067。这多半是程序要写C:\ProgramData下面的目录,或者要读证书私钥,而那个账号没权限。把进程的权限问题和代码问题分开看,能少绕不少弯路。


依赖服务没起来

sc qc的输出里DEPENDENCIES那一行列出了前置服务。依赖链上任何一环是禁用状态,或者它自己启动失败,本服务就一定起不来,而且弹窗上完全看不出是依赖出的问题。

sc qc MyService
sc enumdepend MyService 1024
sc query RpcSs

把DEPENDENCIES里的每一项都sc query一遍,状态不是RUNNING的先处理掉。这一步花不了两分钟,排在最前面查反而最省事。


1053的超时要怎么调

确认程序只是启动慢、并没有崩溃,才轮到调超时。注册表路径HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control,在这个Control项下新建一个DWORD值,名字叫ServicesPipeTimeout,基数选十进制,数值填60000,单位是毫秒。系统默认的判定值是30000。

reg add HKLM\SYSTEM\CurrentControlSet\Control /v ServicesPipeTimeout /t REG_DWORD /d 60000 /f

这个改动要重启才生效,而且是全局的,所有服务都跟着放宽,开机启动链也会被拖长。真正解决启动慢还得回到程序本身:OnStart里不要做耗时初始化,把重活挪到后台线程,或者调用RequestAdditionalTime(60000)主动向服务控制管理器申请更多时间。用.NET 6.0、7.0、8.0、9.0这些版本配UseWindowsService托管时同样适用。


binPath写错埋的雷

sc create的时候binPath里带空格和带引号的处理挺反人类:binPath=后面必须有一个空格,路径本身要用双引号包起来,路径内部再出现引号要写成反斜杠加引号转义。装的时候没注意,BINARY_PATH_NAME被截断,服务一启动就1067,而报错里不会提示路径有问题。

sc create MyService binPath= "\"C:\Program Files\App\App.exe\" --config C:\App\cfg.yaml" start= auto
sc config MyService binPath= "\"C:\Program Files\App\App.exe\" --config C:\App\cfg.yaml"

改完用sc qc回读一次,确认BINARY_PATH_NAME完整。这几个命令在Windows Server 2016、2019、2022、2025以及Windows 10、Windows 11上行为一致,build 10.0.14393、10.0.17763、10.0.19045、10.0.26100这几个号都试过。


剩下的几类边角

动态库缺失同样表现为1067,尤其是VCRUNTIME140.dll、MSVCP140.dll这类运行库。手动跑一遍会直接在控制台报出来,比翻事件日志快。缺哪个装哪个的Visual C++ Redistributable,年份对不上也会失败,2015、2019、2022三个版本的运行库二进制是兼容的,装较新的那个即可。

杀软拦截、磁盘写满、ProgramData目录只读,这几样查起来都是几分钟的事,排在靠后的位置即可。系统自带服务出问题的话,跑一次sfc /scannow把系统文件修一遍,比手动替换dll稳当。


几条常用命令

sc query MyService
sc queryex MyService   rem 输出里带PID
tasklist /svc /fi "SERVICES eq MyService"
sc start MyService
sc stop MyService

sc queryex能拿到服务的PID,接着用tasklist看这个进程到底卡在哪一步。PowerShell里对应的就是Get-Service和Restart-Service -Force,后者在服务卡在STOP_PENDING状态时比sc stop管用。

以上命令与行为在Windows Server 2016到2025、Windows 10与Windows 11上均一致,数据截至2026年10月。真到线上排查时,先把事件日志捞出来再动手,比反复点启动按钮省时间。