必须将bind-address改为0.0.0.0或具体ip,因mysql默认仅监听127.0.0.1,拒绝所有远程tcp连接;需同步配置用户host为'%'或指定ip、放行3306端口并确保客户端使用-h参数指定服务器ip。

bind-address 必须改成 0.0.0.0 或具体 IP
MySQL 默认只监听 127.0.0.1,这意味着它拒绝所有来自本机以外的 TCP 连接。即使用户权限全开、防火墙放行,远程连接仍会卡在“连接超时”或“Can’t connect to MySQL server”。
修改配置前先确认当前监听地址:
sudo netstat -tlnp | grep mysql
如果输出中只有 127.0.0.1:3306,就必须改配置。编辑文件:
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
找到 bind-address 行,改为:
-
bind-address = 0.0.0.0(允许所有网卡,测试可用) - 或更安全的:
bind-address = 192.168.1.100(仅绑定内网 IP) - 绝对不要留空、不要注释掉、不要写成
localhost
改完必须重启服务:sudo systemctl restart mysql。不重启,配置无效。
用户 host 字段必须是 '%' 或具体 IP,不能是 'localhost'
MySQL 的用户是 'user'@'host' 成对存在的。'root'@'localhost' 和 'root'@'%' 是两个完全不同的账号,权限互不影响。远程连接用的是 TCP,匹配的是 host 为 % 或对应 IP 的记录,不是 localhost。
常见错误操作:
- 直接执行
GRANT ... TO 'root'@'%' ...,但系统里根本没有'root'@'%'这条记录 → 报错ERROR 1410 (42000): You are not allowed to create a user with GRANT - 误以为
UPDATE mysql.user SET Host='%' WHERE User='root'就够了 → 忘记FLUSH PRIVILEGES,且可能因 plugin 字段不匹配导致认证失败
推荐做法(MySQL 8.0+):
CREATE USER 'remote_user'@'%' IDENTIFIED WITH mysql_native_password BY 'StrongPass123!';<br>GRANT SELECT, INSERT, UPDATE ON app_db.* TO 'remote_user'@'%';<br>FLUSH PRIVILEGES;
注意:mysql_native_password 是关键,避免客户端因默认 caching_sha2_password 插件不兼容而报 Authentication plugin 'caching_sha2_password' cannot be loaded。
防火墙必须放行 3306 端口,且规则要永久生效
Linux 上仅开放端口不等于能连通。UFW 或 firewalld 的临时规则在重启后会丢失,而很多教程漏写 --permanent 参数。
Ubuntu(UFW):
- 检查状态:
sudo ufw status verbose - 正确放行:
sudo ufw allow 3306/tcp(自动持久化)
CentOS/RHEL(firewalld):
- 错误写法:
firewall-cmd --add-port=3306/tcp(重启即失效) - 正确写法:
firewall-cmd --permanent --add-port=3306/tcp && firewall-cmd --reload
云服务器(如阿里云、腾讯云)还需额外在控制台安全组中放行 3306 入方向规则——这个步骤最容易被忽略,且错误提示常被误判为数据库配置问题。
远程连接命令里 -h 参数不能省,且不能填 localhost
从客户端机器执行连接时,mysql -u remote_user -p 默认走本地 socket,不会触发 TCP 连接,也就绕过了你刚配的所有远程设置。
必须显式指定服务器 IP:
- 正确:
mysql -h 192.168.1.100 -u remote_user -p - 错误:
mysql -h localhost -u remote_user -p(仍连本地 socket) - 错误:
mysql -u remote_user -p(同上)
如果服务器有公网 IP,且你已配好安全组和 NAT 映射,才可用公网 IP 连接;内网环境务必用内网 IP,否则 DNS 或路由可能导致连接失败。
真正卡住人的地方,往往不是某一步做错了,而是多个环节都差一点:bind-address 没改、用户 host 写成 localhost、防火墙没 reload、客户端连的是 localhost 而非真实 IP —— 四个条件缺一不可,且每个都有隐蔽的“看似生效实则无效”的状态。











