create user 'u'@'localhost'是唯一可靠方式,因mysql对字面量'localhost'有硬编码处理:客户端不带-h参数时强制走unix socket、跳过tcp/ip;'u'@'127.0.0.1'或'%'始终走tcp,无法等效替代。

直接结论:CREATE USER 'u'@'localhost' 是唯一可靠方式。不是配置文件改几行就能生效,必须从账号创建源头就锁定 host 字段为字面量 localhost,否则所有后续操作都可能绕过。
为什么 'u'@'localhost' 才真正走 Unix Socket?
MySQL 服务端对 'user'@'localhost' 有硬编码逻辑:客户端不带 -h 参数连接时,强制查找 Unix domain socket(如 /var/run/mysqld/mysqld.sock),完全跳过 TCP/IP 协议栈。这不是 DNS 解析或配置开关,是内建行为。
-
'u'@'127.0.0.1'或'u'@'%'始终走 TCP,哪怕bind-address = 127.0.0.1或防火墙封了 3306 端口,也拦不住这个路径 - GUI 工具(如旧版 DBeaver、Navicat)常把
localhost自动解析成127.0.0.1,导致你建了'u'@'localhost'却连不上——它根本没尝试 socket - 验证是否真走 socket:连接后执行
\s,看Connection:行输出必须是Localhost via UNIX socket,不是127.0.0.1 via TCP/IP
已有用户不能 UPDATE mysql.user SET host = 'localhost'
MySQL 8.0+ 禁止直接更新 mysql.user 表的 Host 字段。执行 UPDATE 后该账号不会“变成本地”,而是彻底失效:登录时报 Access denied for user 'u'@'old_host',即使 SELECT User, Host FROM mysql.user 还能查到记录。
- 正确做法是先
DROP USER 'u'@'old_host',再CREATE USER 'u'@'localhost' IDENTIFIED BY 'pwd' - 授权也必须严格匹配:
GRANT SELECT ON db.* TO 'u'@'localhost';对'u'@'%'授权无效 - 执行
FLUSH PRIVILEGES,尤其在DROP后建议显式刷新
命令行和应用代码里别写死 host='127.0.0.1'
本地测试时,mysql -u u -p 默认走 localhost 语义,触发 socket;但一旦加了 -h 127.0.0.1,就强制走 TCP,绕过你设的 'u'@'localhost' 权限规则。
- Python、Node.js 等应用代码常见错误:
host='127.0.0.1', port=3306→ 走 TCP,匹配不到'u'@'localhost' - 正确写法:
host='localhost'(依赖驱动实现),或更可靠的是显式传 socket 路径:unix_socket='/var/run/mysqld/mysqld.sock' - 某些旧版客户端不支持
host='localhost'fallback,必须手动指定--socket参数或留空 host 字段(部分驱动支持)
最容易被忽略的点是:你建了 'u'@'localhost',但客户端工具或脚本里写了 -h 127.0.0.1 或 host='127.0.0.1',整个限制就形同虚设——MySQL 根本不会去查这条记录。











