根本原因是localhost强制走Unix socket而127.0.0.1强制走TCP/IP,导致socket路径不匹配或权限/账号(如'root'@'localhost'与'root'@'127.0.0.1')错配。

PHP 使用 localhost 连接 MySQL 失败但 127.0.0.1 成功,根本原因不是网络不通,而是连接协议自动切换导致的路径/权限错配——localhost 触发 Unix socket 连接,127.0.0.1 强制走 TCP/IP。
为什么 localhost 会走 socket 而不是 TCP
MySQL 客户端库(包括 PHP 的 mysqli 和 PDO_MySQL)对 localhost 有特殊处理:只要 host 字符串是字面量 "localhost"(不含端口),就忽略 TCP 设置,直接尝试 Unix domain socket。这跟 DNS 解析无关,也跟 hosts 文件里怎么写 localhost 没关系。
- socket 路径必须和 MySQL 实际监听的 sock 文件完全一致,否则报
Can't connect to local MySQL server through socket - Windows 下类似逻辑会触发命名管道(named pipe),但 phpEnv 是类 Unix 环境,只关心 socket
- 即使 MySQL 同时监听
127.0.0.1:3306和 socket,PHP 用localhost也不会去连 TCP
检查并修正 php.ini 中的 socket 路径
phpEnv 默认不会自动同步 MySQL 的 socket 路径,必须手动核对。先查 MySQL 实际 sock 位置:
mysql -u root -p -e "SHOW VARIABLES LIKE 'socket';"
输出类似 /usr/local/phpenv/mysql/var/mysql.sock 或 /tmp/mysql.sock。然后在 php.ini 中找以下两处配置项:
立即学习“PHP免费学习笔记(深入)”;
-
mysqli.default_socket:对应mysqli_connect()和面向过程调用 -
pdo_mysql.default_socket:对应PDO方式连接 - 两个值必须严格等于上一步查到的路径,不能留空、不能写错斜杠方向、不能漏掉扩展名
- 改完后重启 Web 服务(如 Apache/Nginx)或 php-fpm,仅 reload 不生效
快速验证是否 socket 路径问题
临时绕过配置,显式指定 socket 路径测试:
$conn = mysqli_connect('localhost', 'root', 'pass', '', 0, '/path/to/mysql.sock');
如果这样能连上,说明就是 php.ini 里没配对;如果仍失败,再看下一步。
- 确认 MySQL 用户对 socket 文件有读写权限(常见于权限被限制在
mysql组内) - 检查
my.cnf中socket=和datadir=路径是否一致,不一致会导致 MySQL 自己都找不到 sock - phpEnv 若使用多版本 MySQL,注意当前启用的是哪个版本,sock 路径可能随版本变化
不想调 socket?直接用 127.0.0.1 就行
这不是“妥协”,而是更可控的选择。尤其在开发环境频繁切换 MySQL 版本时,硬编码 socket 路径反而容易出错。
- 把数据库配置中的
host从"localhost"改成"127.0.0.1",所有连接立即走 TCP - TCP 连接不受 socket 权限、路径、用户组限制,只要端口开放、账号密码正确、host 权限允许(如
'root'@'127.0.0.1')就能通 - 性能差异在本地几乎不可测,别信“socket 更快”的模糊说法——现代 Linux 的 loopback TCP 优化极好
- 避免未来因系统升级、phpEnv 更新导致 socket 路径变更而再次中断
真正容易被忽略的是:MySQL 用户权限是按 host 字段区分的。'root'@'localhost' 和 'root'@'127.0.0.1' 是两个独立账号,密码、插件(如 auth_socket)、权限都可能不同。用 127.0.0.1 连不上时,优先查这个,而不是怀疑网络。



















