MySQL中用户是否支持远程登录由user表Host字段决定:'localhost'仅限本地socket连接,'127.0.0.1'走本地TCP,'%'或具体IP才允许远程;还需检查bind-address配置和认证插件兼容性。

怎么确认当前用户是本地还是远程登录的
MySQL 的 user 表里,Host 字段决定用户从哪来——'localhost' 只能本机 socket 连,'127.0.0.1' 走 TCP 但仍是本地环回,而 '%' 或具体 IP(如 '192.168.1.100')才允许远程连。很多人改完权限连不上,第一反应是密码错了,其实是 Host 值没匹配上。
查当前所有用户和来源:
SELECT User, Host FROM mysql.user;
-
Host是'%':任何 IP 都能连(极不推荐生产环境) -
Host是'localhost':远程根本连不上,哪怕你用-h 127.0.0.1也不行(MySQL 会优先走 socket) -
Host是'192.168.1.%':只放行该网段,比'%'安全得多
GRANT 时 Host 写错导致权限不生效
执行 GRANT 命令时,ON 后面的数据库名、TO 后面的用户名和主机必须完全匹配 mysql.user 表里已存在的记录。如果 CREATE USER 'foo'@'%' IDENTIFIED BY 'pw'; 创建了用户,但后续用 GRANT SELECT ON db.* TO 'foo'@'localhost';,这条权限不会加到 'foo'@'%' 上——它们在 MySQL 看来是两个不同用户。
- 先确认目标用户是否存在:
SELECT User, Host FROM mysql.user WHERE User = 'foo';
-
GRANT必须和CREATE USER中的Host一致,比如GRANT SELECT ON db.* TO 'foo'@'%'; - 改完记得
FLUSH PRIVILEGES;,否则权限不加载(虽然多数情况自动刷新,但别赌)
bind-address 和防火墙共同决定能否被远程访问
MySQL 默认绑定 127.0.0.1(即 bind-address = 127.0.0.1),哪怕你给用户开了 '%' 权限,外部也连不到端口。这是网络层拦截,和权限无关。
- 编辑配置文件(通常是
/etc/mysql/mysql.conf.d/mysqld.cnf或/etc/my.cnf),找到bind-address,改成:bind-address = 0.0.0.0
(监听所有接口)或指定内网 IP(如192.168.1.10) - 重启 MySQL:
sudo systemctl restart mysql - 检查端口是否真在监听:
ss -tlnp | grep :3306,确认0.0.0.0:3306或对应 IP 出现在输出里 - 别忘了系统防火墙:
sudo ufw allow 3306(Ubuntu)或sudo firewall-cmd --add-port=3306/tcp --permanent(CentOS)
为什么 root@'%' 仍连不上,但普通用户可以
MySQL 8.0+ 默认用 caching_sha2_password 插件认证,老客户端(比如某些 Python MySQLdb、旧版 Navicat)不支持,会报错 Authentication plugin 'caching_sha2_password' cannot be loaded。而很多教程直接让 root 开 '%',结果连不上还怀疑权限问题。
- 临时解决:把 root 改成兼容插件:
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'your_pw';
- 更稳妥做法:为远程访问单独建用户,不用 root:
CREATE USER 'appuser'@'192.168.1.%' IDENTIFIED BY 'strong_pw'; GRANT SELECT,INSERT ON appdb.* TO 'appuser'@'192.168.1.%';
- 注意:MySQL 8.0 的
GRANT不再隐式创建用户,必须先CREATE USER,否则报错ERROR 1410 (42000): You are not allowed to create a user with GRANT
最常被忽略的是 bind-address 和认证插件的组合问题——权限设对了,网络不通;网络通了,插件不认。这两步得一块儿查,缺一不可。











