服务器:腾讯云 VM-0-16-ubuntu,宝塔面板
技术栈:nginx + PHP + MySQL 5.7.44 + WordPress + Argon
排查日期:2026-09-14
2026.9.14——by Everfades
如果您有宝贵的意见或建议,请发邮件至:everfades1218@gmail.com或everfades@foxmail.com
在使用Typora阅读前,请将文件→偏好设置→Markdown→内联公式 勾选上,以免显示出错!
一、故障时间线
| 时间(CST) | 事件 |
|---|---|
| 迁移期间 | 站点从 IP 49.232.244.149 迁移到域名 www.everfades.cn,运行过 fix-urls.php 做全库 URL 替换 |
| 09-14 04:40 | MySQL binlog flush 失败,binlog_error_action=ABORT_SERVER 触发,MySQL 主动结束运行 |
| 09-14 10:03 | systemctl start mysqld 失败,报 “server quit without updating PID file”,且 .err 日志无任何新记录 |
| 09-14(排查前) | 用户在 WordPress 后台修改固定链接,此后子页面全部 404 |
| 09-14 10:27 | 前台启动 mysqld,定位到 binlog 损坏,MySQL 自动截断修复,成功启动 |
注:404 和 MySQL 崩溃是两个独立的问题,只是碰巧在同一时期暴露。404 由固定链接变更触发,MySQL 崩溃由 binlog 写入失败触发。排查过程中修好 404 之后,才让 MySQL 的问题显露出来。
二、第一层:分类页 404
现象
在 WordPress 后台改过固定链接后https://www.everfades.cn/category/artical/以及其他子页面均返回 404,但everfades.cn首页正常。
关键排查动作:区分 404 的类型
这是整个排查中最省时间的一步。WordPress 站点的 404 有两种,外观不同,原因完全不同:
| 404 外观 | 含义 | 故障层 |
|---|---|---|
| 白底黑字,只有 “404 Not Found” 和 “nginx” | 请求根本没进 PHP,nginx 按字面找文件没找到 | Web server 层(rewrite 规则) |
| 带 Argon 主题的导航栏、配色 | 请求进了 WordPress,但没匹配到内容 | 应用层(固定链接结构 / 分类 slug) |
确认是裸 nginx 404后,方向立刻定死在 rewrite 层,不必再去查分类 slug、分类目录前缀、主题模板这些应用层因素。
原理
WordPress 的pretty permalink是虚拟 URL,磁盘上不存在对应的目录或文件:
- 首页
/→ 对应真实存在的index.php,不需要 rewrite /category/artical/→ 磁盘上没有category/artical/这个目录,必须靠 rewrite 把请求交给index.php,再由 WordPress 内部路由解析成”分类归档页”
nginx 的默认行为是按字面查找路径,找不到就返回自己的 404,PHP 完全不会被执行。
这解释了”首页能开、子页面全部404″这个看似矛盾的现象。
修复
宝塔面板 → 网站 → 点击站点 → 左侧 伪静态 → 下拉框选择 wordpress → 保存。
写入以下规则:
location /
{
try_files $uri $uri/ /index.php?$args;
}
rewrite /wp-admin$ $scheme://$host$uri/ permanent;
核心是 try_files $uri $uri/ /index.php?$args;,三段依次尝试:
$uri—— 找同名真实文件(图片、CSS、JS 走这里,直接由 nginx 返回,不经过 PHP)$uri/—— 找同名真实目录/index.php?$args—— 都没有,把请求连同原查询参数交给 WordPress
第二条 rewrite /wp-admin$ 是给后台地址补尾斜杠,避免 /wp-admin 不带斜杠时的跳转异常。
收尾动作
伪静态生效后,进 WordPress 后台 设置 → 固定链接,什么都不改直接点”保存更改”。这会让 WordPress 重建内部 rewrite 规则表,与 nginx 侧对齐。
三、第二层:Error establishing a database connection
伪静态修好后,再次打开子页面,页面报这个错Error establishing a database connection。
这条报错来自 WordPress 本身(wp-db.php),能看到它意味着:
- nginx 正确地把请求转给了 PHP
- PHP 正常执行
- WordPress 代码被加载,走到了连接数据库这一步
也就是说第一层的 rewrite 问题确实解决了,现在暴露的是下一个独立问题。
服务状态
× mysqld.service - LSB: start and stop MySQL
Active: failed (Result: exit-code) since Mon 2026-09-14 10:03:57 CST
Process: 987 ExecStart=/etc/init.d/mysqld start (code=exited, status=1/FAILURE)
mysqld[987]: Starting MySQL.... * The server quit without updating PID file
MySQL 服务处于 failed 状态。数据库连不上的原因很直接:服务根本没在运行。
“The server quit without updating PID file” 是 init 脚本的通用报错 —— mysqld 进程退出了,PID 文件没生成,init 脚本只能报告这个表象。它不包含任何根因信息,必须去看 MySQL 自己的错误日志。
四、第三层:MySQL 启动即失败
.err 日志里的最后一条崩溃记录:
2026-09-13T20:40:08.486997Z 27638 [ERROR] /www/server/mysql/bin/mysqld:
Binary logging not possible. Message: An error occurred during flush stage
of the commit. 'binlog_error_action' is set to 'ABORT_SERVER'.
Server is being stopped.
20:40:08 UTC - mysqld got signal 6 ;
报错原因:MySQL 写 binlog(二进制日志)失败时,binlog_error_action 决定后续行为。默认值 ABORT_SERVER 的含义是——binlog 一旦写不进去,MySQL 宁可主动停止服务,也不继续接受写入。因为继续跑会导致 binlog 记录与实际数据不一致,会破坏主从复制和时间点恢复的可靠性,比停机更严重。
后面的 signal 6(SIGABRT)和一大段 backtrace 是这次主动 abort 的产物,不是独立的 bug,也不指向硬件故障——尽管日志里那段模板文字提到了 “bug”、”corrupt”、”malfunctioning hardware”。这是 MySQL 崩溃处理的通用输出。
binlog flush 失败最常见的诱因是磁盘空间不足,所以第一假设是磁盘满,但磁盘空间还有40多个G,不可能不够用。
触发 binlog 写入失败还有其他可能:
| 可能原因 | 为什么 df -h 看着正常 |
|---|---|
| tmpdir 所在分区满 | /tmp 常是小容量 tmpfs,与 /www 是不同挂载点 |
| 文件系统被内核挂成只读 | 云盘 I/O 错误后内核 remount 为 ro 自保,空间照常显示 |
| inode 耗尽 | df -h 看空间,要 df -i 才看得到 inode |
| 数据目录属主/权限错误 | 与容量无关 |
| binlog index 与实际文件不一致 | 与容量无关 |
随后我在”VM-0-16-ubuntu.err”中查看日志,注意到最新一条日志截止到2026-09-13 20:40:08 UTC,换算一下就是2026-09-14 04:40:08 CST(UTC+8),随后再没有任何日志。
这个空白本身就是诊断信息。 能写进 .err 的前提是 mysqld 已经初始化到了错误日志子系统。如果它在更早的阶段就失败——解析配置、检查数据目录、打开日志文件——报错只会走 stderr,被 init 脚本吞掉或丢进 systemd journal,.err 里一个字都不会留。
所以”启动失败但无日志”直接指向:失败发生在日志可写之前。
前台启动
绕开 init 脚本和日志重定向,在终端查看报错:
/www/server/mysql/bin/mysqld --user=mysql --console
此处有几点注意:
- 必须带
--user=mysql。以 root 身份运行会在数据目录里生成 root 属主的文件,反过来制造权限问题 --console强制输出到 stderr,绕过log-error重定向- 会占住终端。启动成功就一直挂着(说明问题在 init 脚本层),失败则立即退出并打印原因
binlog 尾部损坏
真正的原因立刻显现:
2026-09-14T02:27:31.201920Z 0 [Note] Recovering after a crash using mysql-bin
2026-09-14T02:27:31.290350Z 0 [ERROR] Error in Log_event::read_log_event():
'read error', data_len: 66, event_type: 19
2026-09-14T02:27:31.294421Z 0 [Note] Crashed binlog file ./mysql-bin.000012
size is 21385216, but recovered up to 21385047.
Binlog trimmed to 21385047 bytes.
完整的链路如下:
- 今早 04:40 的
ABORT_SERVER是在 binlog 写入中途发生的 mysql-bin.000012尾部因此留下一个残缺的 event —— 文件实际大小 21385216 字节,但最后一个完整 event 只到 21385047 字节,多出 169 字节的半截数据- 此后每次启动,MySQL 走到 “Recovering after a crash using mysql-bin” 阶段,读到这个坏 event,
read_log_event()报错,启动中止 - 这个阶段发生在错误日志子系统就绪之前,所以
.err里没有任何记录
两个疑点在这里合上了:启动失败的原因,以及日志为什么是空的,是同一件事的两面。
修复:MySQL 自行完成
这次前台启动过程中,MySQL 把损坏部分处理掉了:
Binlog trimmed to 21385047 bytes.
把 binlog 截断到最后一个完整 event 的边界。这个操作是持久化的——写回了文件,坏 event 不会再挡路。
同时 InnoDB 的崩溃恢复也顺利跑完:
InnoDB: Database was not shutdown normally!
InnoDB: Starting crash recovery.
InnoDB: Rollback of non-prepared transactions completed
InnoDB: 5.7.44 started; log sequence number 8237452629
最后:
/www/server/mysql/bin/mysqld: ready for connections.
Version: '5.7.44-log' socket: '/tmp/mysql.sock' port: 3306
数据没有丢失。 InnoDB 的 redo log 保证了已提交事务的持久性,被截断的只是 binlog 尾部那个未完成事务的记录。
后续只需要Ctrl+C 干净关闭前台进程,然后 systemctl start mysqld 走正常服务启动即可,所有子界面均恢复正常了~
附:两条关键日志原文
触发点——今早 04:40 CST 的崩溃:
2026-09-13T20:40:08.486997Z 27638 [ERROR] /www/server/mysql/bin/mysqld:
Binary logging not possible. Message: An error occurred during flush stage
of the commit. 'binlog_error_action' is set to 'ABORT_SERVER'.
Server is being stopped.
根因与自动修复——10:27 CST 前台启动:
2026-09-14T02:27:31.201920Z 0 [Note] Recovering after a crash using mysql-bin
2026-09-14T02:27:31.290350Z 0 [ERROR] Error in Log_event::read_log_event():
'read error', data_len: 66, event_type: 19
2026-09-14T02:27:31.294421Z 0 [Note] Crashed binlog file ./mysql-bin.000012
size is 21385216, but recovered up to 21385047.
Binlog trimmed to 21385047 bytes.
2026-09-14T02:27:31.460300Z 0 [Note] /www/server/mysql/bin/mysqld: ready for connections.



