必须显式指定'localhost'创建仅本地访问账户,因其强制走Unix socket连接且与'127.0.0.1'(TCP)严格区分;CREATE USER 'admin'@'localhost' IDENTIFIED BY 'pwd'是唯一安全做法。

创建 localhost 限定账户时必须指定 'localhost' 主机名
MySQL 的用户认证基于 username@host 组合,'root'@'localhost' 和 'root'@'127.0.0.1' 是两个完全不同的账户。只写 CREATE USER 'admin' 不加 @'localhost' 默认会创建 'admin'@'%',允许任意主机连接——这绝不是你想要的。
正确做法是显式声明主机名为 'localhost':
CREATE USER 'admin'@'localhost' IDENTIFIED BY 'your_strong_password';
注意:'localhost' 在 MySQL 中有特殊含义:它强制使用 Unix socket 连接(Linux/macOS)或命名管道(Windows),不走 TCP/IP,天然无法从网络访问。
别用 '127.0.0.1' 替代 'localhost'
如果你误写成 'admin'@'127.0.0.1',虽然 IP 看似本地,但 MySQL 会通过 TCP/IP 协议连接,且该账户可被远程发起的 127.0.0.1 请求匹配(例如 Docker 容器内、某些代理配置下可能绕过预期限制)。
关键区别:
-
'localhost'→ 只响应本地 socket 连接,完全拒绝 TCP 连接请求 -
'127.0.0.1'→ 响应 TCP 连接,只要目标地址是 127.0.0.1 就能匹配,不满足“仅本地”安全要求
验证是否生效,可执行:
SELECT User, Host FROM mysql.user WHERE User = 'admin';
确保结果中 Host 列值为 localhost,而非 127.0.0.1 或 %。
授予权限时要绑定同一 user@host 元组
授权语句中的 ON 子句没问题,但 TO 后必须与创建时完全一致,包括引号和大小写:
GRANT ALL PRIVILEGES ON *.* TO 'admin'@'localhost' WITH GRANT OPTION;
常见错误:
- 漏掉
@'localhost',变成GRANT ... TO 'admin'→ 实际授给'admin'@'%'(如果存在) - 大小写不一致,如
'ADMIN'@'localhost'→ 账户不存在,报错ERROR 1133 (42000): Can't find any matching row in the user table - 忘记执行
FLUSH PRIVILEGES;→ 权限变更不立即生效(MySQL 8.0+ 多数情况自动刷新,但显式执行更稳妥)
验证是否真无法远程访问
最直接的检验方式是:从另一台机器(或本机不同终端)尝试 TCP 连接:
mysql -h 127.0.0.1 -u admin -p
如果返回 ERROR 1045 (28000): Access denied for user 'admin'@'127.0.0.1',说明成功隔离;若能登录,大概率是误建了 'admin'@'127.0.0.1' 或 'admin'@'%'。
另外检查是否意外启用了 skip-name-resolve:若开启,MySQL 不做 DNS 解析,'admin'@'localhost' 依然有效;但若关闭且系统 hosts 配置异常,极少数情况下可能触发意外解析——不过这不是常态,优先排查账户定义本身。
真正容易被忽略的是:MySQL 安装后默认存在的 'root'@'localhost' 和 'root'@'127.0.0.1' 往往共存,新账户务必保持命名和主机名的一致性,否则权限模型会变得难以追踪。


















