MySQL仅通过CREATE USER 'u'@'localhost'配合skip-networking=ON、客户端不指定-h 127.0.0.1实现Unix Socket连接限制,三者缺一不可,且不支持按socket路径做用户级白名单。

MySQL 本身不支持“按 Unix Socket 路径限制用户”或“只允许某台应用服务器走特定 socket 文件”的机制。所谓“只允许特定应用服务器通过 Unix Socket 连接”,实际是靠三重控制协同实现的:服务端禁用 TCP、账号 host 绑定为 'localhost'、客户端强制使用 socket 文件且不触发 TCP 回退。缺一不可,任意一环松动就会被绕过。
为什么 'localhost' 账号是唯一可靠入口
MySQL 对 'localhost' 字符串做了硬编码特殊处理:只要账号的 Host 是字面量 'localhost'(不是 '127.0.0.1',也不是通配符 '%'),且客户端未显式指定 -h 127.0.0.1 或 --protocol=TCP,就会强制走 Unix Socket——路径由服务端 socket 变量决定,而非客户端自由选择。
- 必须一步创建:
CREATE USER 'app'@'localhost' IDENTIFIED BY 'pwd';,不能先建'app'@'%'再改 Host(MySQL 8.0+ 禁止 UPDATE mysql.user.Host) - 授权也必须严格匹配:
GRANT SELECT ON db.* TO 'app'@'localhost';,对'app'@'%'授权完全无效 - 验证连接类型:登录后执行
\s,确认Connection:行显示Localhost via UNIX socket
skip-networking = ON 才真正关闭 TCP
仅设 bind-address = 127.0.0.1 是陷阱——它仍监听 127.0.0.1:3306,任何本机进程(包括恶意脚本)都能通过 TCP 连接,完全没达到“只走 socket”的目的。
- 正确做法:在
[mysqld]段中设置skip-networking = ON,并**注释掉或删除bind-address行**(否则skip-networking会被忽略) - 重启后验证:
netstat -tlnp | grep :3306应无输出;mysql -h 127.0.0.1 -u app -p必须报错Can't connect to MySQL server on '127.0.0.1' - 确保
socket路径存在且可访问:SHOW VARIABLES LIKE 'socket';→ 查路径;ls -l /var/run/mysqld/mysqld.sock→ 看权限是否为srwxrwxrwx,属主mysql:mysql
客户端必须杜绝 TCP fallback
即使服务端和账号都配对了,客户端一个参数写错就退回 TCP,直接失效整个防护逻辑。
- 命令行测试:用
mysql -u app -p或mysql -u app -p -h localhost(注意是localhost字符串,不是 IP);绝对避免-h 127.0.0.1 - 应用代码中:Python 的
mysql-connector-python或pymysql应显式传unix_socket='/var/run/mysqld/mysqld.sock';Node.js 的mysql2同理用socketPath选项 - GUI 工具(如 DBeaver)常默认把
localhost解析成127.0.0.1,必须手动清空 Host 字段,或填入 socket 路径(部分驱动支持)
最易被忽略的点是:socket 文件本身不是认证凭据,它只是通信通道。真正的隔离靠的是 'localhost' 账号 + skip-networking + 客户端不越界这三者咬合。一旦应用服务器上混跑其他程序,或配置文件泄漏了 '%' 账号,防护就形同虚设。


















