直接切入正题:MySQL 8.0 在远程连接方面以“严格限制”著称。默认配置下,完全无法从外部主机连接数据库。要实现远程访问,必须满足以下四个关键条件——用户 host 字段允许通配、密码认证插件兼容、系统防火墙放行、云服务商安全组开放,缺一不可。

确认 root 或目标用户的 host 是否为 %
MySQL 8.0 的 user 表中有一个 host 字段,用于限定用户可以从哪些主机登录。默认情况下 'root'@'localhost' 只允许本机访问。
登录 MySQL 后,执行以下查询来查看:
USE mysql;
SELECT user, host FROM user WHERE user = 'root';
如果返回的 host 值为 localhost,那么远程连接时必将收到 ERROR 1045 (28000): Access denied for user 'root'@'xxx.xxx.xxx.xxx' 错误。
那么如何解决?需要注意以下两点:
- 直接修改 root 用户的 host 并非最佳做法:虽然执行
UPDATE user SET host = '%' WHERE user = 'root';后再FLUSH PRIVILEGES;即可生效,但这会带来严重的安全风险。出于安全考虑,不建议这样做。 - 更安全的方法是创建一个专用远程用户:
CREATE USER 'remote_user'@'%' IDENTIFIED BY 'StrongPass123!';。这样能够更精细地控制权限。 - 还有一个常见的误区:MySQL 8.0 已不再支持
GRANT ... IDENTIFIED BY这种一步创建并授权的方式。必须分两步执行,先CREATE USER,再GRANT。
必须将 authentication_plugin 改为 mysql_native_password
MySQL 8.0 对密码认证机制进行了升级,默认使用 caching_sha2_password 插件。但像 Navicat、旧版 JDBC 驱动以及部分 PHP 扩展(如 mysqli)并不支持该插件。连接时会出现错误:Authentication plugin 'caching_sha2_password' cannot be loaded。
解决办法很简单:手动将其改回 mysql_native_password。执行:
ALTER USER 'remote_user'@'%' IDENTIFIED WITH mysql_native_password BY 'StrongPass123!';
修改后最好验证一下:
SELECT user, host, plugin FROM user WHERE user = 'remote_user';
确保返回的 plugin 字段显示为 mysql_native_password,否则仍然无法连接。
这里有两个细节值得单独强调:
- 不能只修改密码(
ALTER USER ... BY),必须显式使用IDENTIFIED WITH指定认证插件。 - 如果执行命令时遇到
ERROR 1820 (HY000),说明密码策略过于严格或密码已过期。可以临时执行SET GLOBAL validate_password.policy = LOW;来降低策略(仅限调试环境使用)。
检查并开放 3306 端口(本地防火墙与云平台安全组)
即使 MySQL 服务正常运行且用户配置完全正确,只要端口未开放,一切远程连接尝试都将失败。CentOS 7 默认使用 firewalld,因此首先需要检查其状态。
执行以下命令添加规则:
firewall-cmd --list-ports
firewall-cmd --zone=public --add-port=3306/tcp --permanent
firewall-cmd --reload
不过,这里有几个容易混淆的地方:
firewall-cmd --list-ports返回为空,并不一定表示端口未开放,可能是规则未以列表形式展示。为稳妥起见,最好使用--add-port显式添加。- 如果你的服务器是阿里云、腾讯云、京东云等云平台的 ECS 实例,仅修改系统防火墙是不够的。必须在云服务商控制台的「安全组」中手动放行 TCP 3306 端口。因为流量在到达系统之前,首先会受到安全组规则的拦截。
- 如果服务器使用的是
iptables而非firewalld,则命令应替换为:iptables -I INPUT -p tcp --dport 3306 -j ACCEPT && service iptables save
确认 bind-address 未被限制在 127.0.0.1
最后一点也是最容易被忽视的“隐形关卡”。MySQL 8.0 默认只监听 127.0.0.1,这意味着它仅响应本机请求。即使前面的用户配置、插件兼容、防火墙规则全部正确,远程仍然无法连接,根源往往就在这里。
打开 /etc/my.cnf 文件,在 [mysqld] 段落中检查或添加以下配置:
bind-address = 0.0.0.0
然后重启 MySQL 服务使其生效:
systemctl restart mysqld
重启后使用 netstat 检查监听状态:
netstat -tlnp | grep :3306
如果输出显示 *:3306 而非 127.0.0.1:3306,则说明 MySQL 已监听所有网络接口。
这里还有三个关键提醒:
- 如果
/etc/my.cnf中根本没有bind-address参数,MySQL 8.0 的默认行为就是绑定127.0.0.1。这一点与 MySQL 5.7 版本不同。 - 修改配置文件后必须重启
mysqld服务,FLUSH PRIVILEGES对该变更无效。 - 如果系统启用了 SELinux(通过
getenforce返回Enforcing来判断),它可能会阻止网络连接。需要额外执行setsebool -P mysqld_connect_any 1来放行。
事实上,大多数人遇到阻塞并非因为某一步做错,而是四个步骤中只完成了三个。例如,打开了防火墙端口却忘了修改 bind-address,或者更改了用户 host 却没有更换认证插件。每一步都需要独立验证,切勿跳跃式操作。
