
mysql root用户默认禁止远程访问,不是bug是安全设计
MySQL 5.7+ 安装后 root@localhost 账户默认只允许本地连接,bind-address 配置和授权语句不配齐,连 mysql -h your_ip -u root 都会报 Access denied for user 'root'@'xxx'。这不是权限没给够,而是连接根本没进到权限校验那步——TCP 连接被拒在门外。
常见错误现象:
• 修改了 my.cnf 里的 bind-address 但还是连不上
• 执行了 GRANT ALL ON *.* TO 'root'@'%'... 却提示 ERROR 1045 (28000)
• SELECT host FROM mysql.user WHERE user='root'; 看到有 % 行,但依然只能本地登录
-
bind-address控制 MySQL 监听哪个网卡,设为0.0.0.0才监听所有 IPv4 地址;设为127.0.0.1(默认)则只响应本地 socket/TCP 回环 - 必须重启
mysqld服务才能使bind-address生效,改完配置不重启等于没改 - Linux 下还要检查防火墙是否放行
3306端口,ufw status或iptables -L看一眼
授权语句必须匹配实际连接来源的 host 字段
MySQL 权限校验时,会把客户端 IP 反向 DNS 解析成 hostname,再和 mysql.user.host 字段比对。所以 'root'@'%' 看似万能,实则受制于网络环境。
- 如果客户端用公网 IP 连,服务端必须存在
'root'@'客户端公网IP'或'root'@'%'—— 但后者极不推荐用于生产 - 用
'root'@'192.168.1.%'比'root'@'%'更安全,也避免 DNS 解析失败导致匹配不到 - 执行
GRANT后必须跟FLUSH PRIVILEGES;,否则新权限不生效(尤其在直接 INSERT 到 mysql.user 表后) - MySQL 8.0+ 不再支持
IDENTIFIED BY PASSWORD语法,要用ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'xxx';
bind-address=0.0.0.0 本身不等于开放 root 远程,只是“开门”
bind-address 是网络层开关,授权是权限层开关,二者缺一不可。更关键的是:开了 0.0.0.0 就等于把数据库暴露在可路由网络里,任何能触达该端口的机器都能尝试爆破。
- 生产环境严禁使用
bind-address = 0.0.0.0+'root'@'%'组合 - 若必须远程管理,优先走跳板机或 SSH 隧道:
ssh -L 3307:127.0.0.1:3306 user@db-server,然后本地连127.0.0.1:3307 - Docker 场景下,
bind-address设为0.0.0.0后,容器外连-p 3306:3306才有效;但宿主机防火墙、云平台安全组仍需单独放行 - 某些云 RDS(如阿里云、腾讯云)直接禁用
bind-address修改,root 远程访问必须通过控制台开通白名单 IP
验证连通性要分两步:先通网络,再通权限
别一连不上就猛改授权,先确认是不是卡在 TCP 层。很多故障其实出在中间网络环节,而不是 MySQL 自身。
- 在客户端执行:
telnet db-ip 3306或nc -zv db-ip 3306,不通说明bind-address/防火墙/安全组有问题 - 通了但报
Access denied,再查服务端:SELECT user,host FROM mysql.user WHERE user='root';,确认是否存在对应 host 记录 - MySQL 错误日志(
/var/log/mysql/error.log或SHOW VARIABLES LIKE 'log_error';)里会明确写 “Host 'x.x.x.x' is not allowed to connect”,这是权限问题;若无此日志,大概率是连接被拒绝在前 - MySQL 8.0 默认认证插件是
caching_sha2_password,老客户端(如旧版 MySQL Workbench、某些 Python pymysql 版本)可能不兼容,需显式指定插件或降级为mysql_native_password
真正麻烦的从来不是怎么开,而是怎么收口——比如某次临时开放的 'root'@'10.0.1.%' 授权,上线后忘了删,半年后被扫描器扫出。










