MySQL 密码轮换后 PHP 应用无法连接:114la 旧文的安全排查指南

维护说明(核查于 2026-09-01): 这不是 114la 的当前安装或支持文档。本文把 2011 年的短文改写为适用于 PHP 与 MySQL/MariaDB 应用的凭据轮换和故障隔离指南。不要从旧快照的下载链接获取软件,也不要把真实密码粘贴到命令行、工单或公开日志中。

密码轮换后应用报“无法连接数据库”,并不等于数据库密码一定错误。服务器账户、应用配置、网络或 Unix socket、TLS 以及 PHP 驱动中的任何一层不匹配,都可能产生相似现象。安全的做法是先固定连接参数和回滚点,再一次只改变一个变量。

“114la”在这里指什么

2011-08-03 的官网网页存档把 114啦描述为一个开源网址导航建站程序,页面标题标为 V1.15;这与旧文中的 PHP 配置路径和 MySQL 字段语境相符。因此,本文把“114la”理解为当时的网址导航 PHP/MySQL 程序。

这份快照只能证明当时页面的自我描述,不能证明旧文给出的配置路径适用于每个版本,也不能证明任何现存下载、域名或分发包仍由原项目维护或安全。截至本次核查,未找到可验证的当前官方维护上游。旧快照只作为出处证据,不是下载或支持入口。

先建立正确的故障模型

把连接拆成四层,避免一看到报错就重复改密码:

  1. 数据库账户: MySQL/MariaDB 账户由用户名和来源主机共同确定,例如 'app_user'@'localhost''app_user'@'10.%' 不是同一个账户。
  2. 应用配置: 数据库端改密不会自动更新 PHP 应用保存的凭据;反过来,只改配置也不会改变数据库账户。
  3. 传输端点: 主机、端口、Unix socket、数据库名和 TLS 参数必须与实际部署一致。在 Unix 系统上,localhost 常会走 socket,而 127.0.0.1 通常走 TCP。
  4. 运行时: PHP 扩展、认证插件支持、容器或虚拟机网络、进程环境和缓存配置都可能影响结果。

变更前的停止条件

只要下列任一项不满足,就先停止,不要在生产环境继续试错:

  • 你没有该应用和数据库账户的明确管理授权。
  • 没有维护窗口,或无法暂时停止/排空写入任务。
  • 没有近期备份、服务商快照或已验证的恢复路径。备份是否可用要由恢复演练确认,而不是只看文件存在;备份方式应按所用版本和存储引擎选择。
  • 不知道原连接参数,或旧凭据没有保存在受控的密码管理器中以便回滚。
  • 应用仍使用数据库 root、远程 root、'user'@'%' 或不必要的全局权限。先让 DBA 建立独立的最小权限应用账户,不要用本次故障当作扩大授权的理由。
  • 无法确认数据库产品和版本。MySQL 与 MariaDB 的账户、认证插件和改密语法并非在所有版本中等价。

记录基线,不记录秘密

与 PHP 应用相同的容器、虚拟机或主机收集版本;从管理员批准的私有控制台记录结果:

mysql --version
php --version
php --modules | grep -E '^(mysqli|pdo_mysql)$'

然后在受控记录中列出精确连接元组,但用秘密管理器引用密码,不要复制密码本身:

项目 必须确认的内容
数据库产品/版本 MySQL 或 MariaDB;精确版本
数据库账户 精确的用户名与账户来源主机
端点 主机名、端口,或 Unix socket 路径
数据库 精确数据库名与字符集要求
传输 是否远程;TLS 模式、CA 和证书主机名
PHP 运行时 PHP 版本、mysqli/pdo_mysql、实际运行容器或主机
配置来源 配置文件、服务环境、容器 secret 或平台 secret 的唯一权威来源

不要在截图、Shell export、聊天、工单或命令参数中放密码。MySQL 官方明确指出,--password=value-pSECRET 形式不安全;只用无值的 --password/-p 触发交互提示,或使用经过保护、由团队批准的登录路径。

从相同运行环境重现连接

先选择与应用完全相同的传输方式。TCP 示例中的值都是占位符:

mysql \
  --protocol=TCP \
  --host='<EXACT_DB_HOST>' \
  --port='<EXACT_DB_PORT>' \
  --user='<LEAST_PRIVILEGE_APP_USER>' \
  --password \
  --database='<EXACT_DB_NAME>' \
  --execute='SELECT CURRENT_USER(), USER(), DATABASE(), @@hostname, @@port, @@version, @@version_comment;'

如果应用配置的是 Unix socket,则单独测试 socket,不要同时给出主机和端口:

mysql \
  --protocol=SOCKET \
  --socket='<EXACT_SOCKET_PATH>' \
  --user='<LEAST_PRIVILEGE_APP_USER>' \
  --password \
  --database='<EXACT_DB_NAME>' \
  --execute='SELECT CURRENT_USER(), USER(), DATABASE(), @@hostname, @@port, @@version, @@version_comment;'

连接成功后,在同一会话中记录账户实际匹配、授权和 TLS 状态;输出应只留在受限的维护记录中:

SELECT CURRENT_USER(), USER(), DATABASE(), @@hostname, @@port, @@version, @@version_comment;
SHOW GRANTS;
SHOW STATUS LIKE 'Ssl_cipher';

CURRENT_USER()显示服务器实际用于权限检查的账户,USER()显示客户端提交的身份。二者不一致时,优先排查账户的来源主机匹配。远程连接应按组织策略使用受信任 CA;在客户端支持时,VERIFY_IDENTITY同时校验证书和主机名。不要为了“先连上”而关闭证书验证。

一次只做一个有边界的轮换

建议的变更单应明确到一个应用账户和一个部署:

  1. 进入维护模式并排空后台写入任务。
  2. 保存 SHOW GRANTS、健康基线和当前配置版本;确认备份/快照及恢复负责人。
  3. 确认要修改的精确账户 'APP_USER'@'EXACT_APP_HOST',不要修改 root,也不要创建远程 root。
  4. 通过服务商控制台、DBA 工具或其他不会把真实秘密写进 Shell 历史、进程列表或聊天记录的批准通道生成并设置随机密码。
  5. 只更新应用的密码引用;不要同时改变主机、端口、数据库名、认证插件或权限。
  6. 完成下面的验收。失败就执行预先写好的回滚,不要继续叠加改动。

现代服务器上的语法形状如下,仅用于展示对象边界,不能不看版本就直接执行

ALTER USER '<APP_USER>'@'<EXACT_APP_HOST>'
  IDENTIFIED BY '<NEW_RANDOM_SECRET>';

示例中的秘密是占位符。真实值仍可能被交互式 SQL 客户端写入历史或审计日志,因此应使用服务商/DBA 批准的秘密安全工具执行。先查阅你所用的精确 MySQL 或 MariaDB 版本文档;旧版本应由 DBA 提供兼容流程,不要从搜索结果复制过时的 SET PASSWORD、直接更新系统表或 FLUSH PRIVILEGES 配方。

MySQL 8.0.14 及之后版本可在满足权限和客户端兼容条件时使用双密码,缩短切换窗口;这不是 MariaDB 通用语法,也不能替代验收。示例同样不得换成真实秘密后粘贴到 Shell 或工单:

ALTER USER '<APP_USER>'@'<EXACT_APP_HOST>'
  IDENTIFIED BY '<NEW_RANDOM_SECRET>'
  RETAIN CURRENT PASSWORD;

ALTER USER '<APP_USER>'@'<EXACT_APP_HOST>'
  DISCARD OLD PASSWORD;

只有在新配置通过验收且所有旧进程已退出后才执行 DISCARD OLD PASSWORD

独立更新应用配置

2011 年旧文提到 /admin/config/cfg_database.php,但没有足够证据证明所有 114la 版本都使用这个路径或字段结构。只在你自己的、已核验的部署中定位真实配置来源;编辑前先备份文件和权限元数据,且不要把文件内容输出到共享终端。

如果应用支持环境变量或部署平台的 secret 注入,现代 PHP 配置的概念映射可以是:

$GLOBALS['database']['db_user'] = getenv('APP_DB_USER');
$GLOBALS['database']['db_pass'] = getenv('APP_DB_PASSWORD');
$GLOBALS['database']['db_name'] = getenv('APP_DB_NAME');
$GLOBALS['database']['db_host'] = getenv('APP_DB_HOST');

这不是 114la 的即插即用补丁。先确认应用会在缺值时安全失败,并确认 PHP 进程确实从批准的 secret 存储获得这些变量。如果旧应用只能读取文件,应通过不会泄露秘密的编辑/部署流程更新,文件放在 Web 根目录之外(若架构允许),只让必要的服务账户读取,且永不提交版本库。不要把 .env 放在可公开访问的目录。

修改后先做语法检查;路径是占位符:

php -l '<PATH_TO_CHANGED_PHP_CONFIG>'

之后只重载确实读取该配置的应用进程。不要把“重启数据库”当作默认修复,也不要为了连接成功而执行 GRANT ALL ON .、使用 % 放宽来源主机,或切换到弱/已弃用的认证插件。

版本、认证插件和 TLS 闸门

  • 先看版本再用 ALTER USER MySQL 与 MariaDB 的支持版本、选项和权限要求不同;双密码的 RETAIN CURRENT PASSWORD/DISCARD OLD PASSWORD仅按 MySQL 对应版本文档使用。
  • 升级客户端,不要默认降级认证。 mysql_native_password在 MySQL 8.0.34 已弃用、8.4 默认禁用、9.0 已移除。若旧 PHP 驱动不认识服务器认证方式,优先升级到受支持的 PHP/MySQL 客户端组合。PHP 文档指出,caching_sha2_password 的完整支持从 PHP 7.4.4 开始;仍需按实际构建和驱动验证。
  • 不要混淆 socket 与 TCP。 PDO MySQL DSN 中,Unix socket 与 host/port是不同连接形式;精确复制应用实际使用的形式。
  • 远程连接要验证 TLS。 保留所需的 TLS 模式、CA 和证书主机名。证书错误是要修复的信任或主机名问题,不是关闭验证的理由。

按错误类别收敛问题

现象 先检查 不要做
Access denied for user ... 密码引用、user@host匹配、账户锁定/过期、应用是否仍读旧 secret 重复改 root 密码或放宽到 %
Unknown database 精确数据库名、大小写和该账户授权 新建一个同名空库来掩盖错误
Connection refused/超时 主机、端口、监听、容器网络、防火墙和服务状态 先改数据库密码
No such file or directory(socket) 实际 socket 路径;应用是否把 localhost解释为 socket 随意创建 socket 文件
不支持认证方式/插件 服务器插件、PHP 驱动与版本兼容性 习惯性启用 mysql_native_password
TLS/证书校验失败 CA、证书链、主机名、客户端 TLS 模式和时钟 关闭证书校验
CLI 成功、PHP 失败 PHP 实际容器/用户、扩展、配置来源、长驻进程和部署缓存 继续轮换数据库密码

日志只保留排查所需的时间、错误类别/代码和请求关联标识;公开或共享前去除密码、连接串、主机、用户名、数据库名、绝对路径、Cookie 和令牌。不要把原始异常页或完整配置上传到论坛。

验收与回滚

按顺序完成一个有边界的验收:

  1. 从应用相同运行环境,用提示式密码输入执行只读连接测试。
  2. 让应用使用新 secret,运行 php -l,再重载必要的 PHP/worker 进程。
  3. 检查一个无需敏感数据的只读页面或健康检查;若业务允许,在专用测试记录上完成一次创建、读取、更新、删除并清理测试数据。
  4. 确认后台任务/队列恢复、没有新的认证错误,SHOW GRANTS与变更前一致,远程连接仍使用预期 TLS。
  5. 观察一个预先约定的窗口;若使用 MySQL 双密码,确认所有旧进程退出后再丢弃旧密码。

如果失败,停止写入,恢复上一版应用配置引用;若数据库端已取消旧密码,由授权 DBA 通过秘密安全通道把精确应用账户恢复到旧凭据,然后重新验证。不要为单纯的凭据不匹配恢复整库备份。只有数据本身被改坏或丢失时,才进入已演练的数据恢复流程。

维护者检查清单

  • [ ] 有授权、维护窗口和恢复负责人。
  • [ ] 备份/快照已验证可恢复,旧配置和文件权限可回滚。
  • [ ] 记录了精确的 user@host、主机/端口或 socket、数据库名、PHP/数据库版本和 TLS 要求。
  • [ ] 使用独立最小权限应用账户;没有远程 root、% 放宽或全局 GRANT ALL
  • [ ] 密码只经 secret 管理器、提示式客户端或批准的 DBA 通道处理,未进入命令行、Git、聊天或公开日志。
  • [ ] 一次只改密码引用,未同时更换端点、权限或认证插件。
  • [ ] CLI、PHP 应用、队列、授权和 TLS 均通过验收;旧密码按计划撤销。
  • [ ] 日志已去敏,临时测试文件和测试数据已清理。

参考资料

2011 年原文存档(仅供出处追溯)

以下内容保留了导出源中用户可见的正文、换行、标点和嵌套代码围栏;仅规范化了行尾空白,并作了三处窄范围安全替换:历史数据库用户名、历史密码值和历史数据库名分别替换为明确占位符。未经删改的原始值仍只存在于 source_export/Git 来源记录中,不应进入维护页面、命令或日志。

这段旧文中的“直接修改配置并询问空间商”是历史材料,不是当前建议:它没有备份、最小权限、secret 处理、版本、TLS、验证或回滚闸门。

MySQL改密码, 114la无法连接数据库


路径为/admin/config/cfg_database.php 这个文件
 例如:
 $GLOBALS [‘database’] [‘db_user’] = ‘[historical database user redacted]’; 数据库用户名
 $GLOBALS [‘database’] [‘db_pass’] = ‘[historical password value redacted]’; 数据库密码
 $GLOBALS [‘database’] [‘db_name’] = ‘[historical database name redacted]’; 数据库名
 $GLOBALS [‘database’] [‘db_host’] = ‘localhost’; 数据库地址
 可以手动修改。
 咨询下空间商数据库正确信息,按提示填入进去就可以了。

Leave a Reply