必须用'root'@'localhost',因MySQL对字面量localhost硬编码处理:客户端不带-h时强制走Unix socket(如/var/run/mysqld/mysqld.sock),跳过TCP/IP;而'root'@'127.0.0.1'走TCP回环,受网络层影响,且与前者为独立账号。

必须用 'root'@'localhost',不是 'root'@'127.0.0.1'
MySQL 对字面量 localhost 有硬编码特殊处理:只要账号是 'root'@'localhost',客户端不带 -h 参数时,就会强制走 Unix socket(如 /var/run/mysqld/mysqld.sock),完全跳过 TCP/IP。而 'root'@'127.0.0.1' 是明确走 TCP 回环,受 bind-address、防火墙、DNS 解析影响,且和 'root'@'localhost' 是两个独立账号——建了后者,前者仍可能被绕过。
- 常见错误:用
UPDATE mysql.user SET Host = 'localhost'修改已有 root 账号 → MySQL 8.0+ 禁止该操作,执行后账号永久失效(SELECT还能查到,但登录一律报Access denied) - 正确做法:先
DROP USER 'root'@'%'(或其它非本地 host),再CREATE USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'strong-pass' - 授权必须严格匹配:
GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION,对'root'@'%'授权无效
FLUSH PRIVILEGES 不是可选,是必须
权限变更后不执行这句,新连接大概率报 Access denied,旧连接也可能沿用旧缓存规则。这不是“建议”,而是 MySQL 权限系统的工作机制——CREATE USER 和 GRANT 会自动刷新部分缓存,但 DROP USER 后必须显式 FLUSH PRIVILEGES 才能确保服务端彻底丢弃旧记录。
- 执行顺序不能错:删账号 → 建新账号 → 授权 →
FLUSH PRIVILEGES - 验证是否生效:本地执行
mysql -u root -p(不加-h),成功后立刻运行SELECT CURRENT_USER();→ 必须返回root@localhost;若返回root@127.0.0.1或其他值,说明匹配到了别的账号 - 检查当前所有 root 账号:
SELECT User, Host FROM mysql.user WHERE User = 'root';,结果应只含localhost(或127.0.0.1,但不推荐)
验证是否真走 socket,别信“连得上”就等于配置对了
连上不等于走的是套接字。很多工具(尤其 Windows 下老版 Navicat、DBeaver)默认把 localhost 解析成 127.0.0.1,导致你建了 'root'@'localhost',它却走 TCP 并失败——或者更糟:你误以为限制生效了,其实只是客户端行为不一致。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
- 命令行验证最可靠:
mysql -u root -p(省略-h)→ 登录后执行\s或STATUS,看Connection:行:
✅Localhost via UNIX socket→ 正确
❌127.0.0.1 via TCP/IP→ 错误,说明连的是'root'@'127.0.0.1'或客户端强制走 TCP - GUI 工具出问题时,要么换支持显式 socket 路径的客户端(如 MySQL Workbench),填
--socket=/var/run/mysqld/mysqld.sock;要么额外建一个'root'@'127.0.0.1'用户(但违背“仅 socket”初衷) - 脚本或应用代码里也常踩坑:
host='127.0.0.1'就是走 TCP,必须用host='localhost'(依赖驱动实现)或直接传unix_socket路径
别忘了禁用 skip_name_resolve 和检查 bind-address
即使账号设对了,如果 MySQL 配置不当,socket 逻辑也可能被干扰。例如 skip_name_resolve = OFF(默认)时,MySQL 会对客户端 IP 做 DNS 反查,若解析慢或失败,可能延迟拒绝或误判 host;而 bind-address = 0.0.0.0 虽不影响 socket 登录,但会让 TCP 监听暴露,增加被扫描风险。
- 推荐配置:
skip_name_resolve = ON(避免 DNS 干扰 host 匹配) +bind-address = 127.0.0.1(限制 TCP 仅监听回环) - 改完 my.cnf 后必须重启:
sudo systemctl restart mysql,否则bind-address不生效 - 重启后验证监听:
ss -tlnp | grep :3306→ 应只显示127.0.0.1:3306,不出现*:3306或公网 IP
实际最难控制的,是客户端行为——尤其是 GUI 工具自动解析 localhost 成 127.0.0.1,以及应用代码里硬编码 host='127.0.0.1'。账号层面的限制只是第一道门,真正锁死 socket 登录,得从服务端配置、账号定义、客户端调用三处同时卡死。










