mysql 8.0 默认拒绝远程连接,根本原因是 bind-address 限制监听地址且 root 用户仅允许 localhost 登录;需同时修改配置文件 bind-address 为 0.0.0.0(或注释)并创建带 '%' 或指定 ip 的远程用户授权。

MySQL 8.0 默认拒绝远程连接,根本原因是 bind-address 和用户权限双限制
装完 MySQL 8.0 直接用 mysql -h 服务器IP -u root -p 连不上?不是密码错,也不是防火墙挡着——大概率是 MySQL 自己“锁死了”监听地址,且 root 用户默认只允许 localhost 登录。这两个限制必须同时改,缺一不可。
常见错误现象:ERROR 2003 (HY000): Can't connect to MySQL server on 'x.x.x.x' (113) 或 ERROR 1045 (28000): Access denied for user 'root'@'xxx.xxx.xxx.xxx'。前者是连不到服务端口,后者是连到了但被权限拒绝。
- 确认 MySQL 当前监听地址:
sudo netstat -tlnp | grep :3306,如果只显示127.0.0.1:3306,说明bind-address没放开 - 修改配置文件
/etc/mysql/mysql.conf.d/mysqld.cnf(Ubuntu/Debian)或/etc/my.cnf(CentOS),把bind-address = 127.0.0.1改成bind-address = 0.0.0.0,或直接注释掉这行 - 重启服务:
sudo systemctl restart mysql(Ubuntu)或sudo systemctl restart mysqld(CentOS)
CREATE USER 和 GRANT 的顺序不能反,MySQL 8.0 必须显式创建远程用户
MySQL 8.0 废弃了 INSERT INTO mysql.user 这类直接操作系统表的方式,也不再允许对 root@localhost 直接 GRANT 远程访问权限。你必须新建一个明确绑定远程主机的用户,否则 GRANT 会静默失败或不生效。
使用场景:调试阶段想用本地 Navicat / TablePlus 连服务器数据库;CI/CD 流水线需要从构建机访问测试库。
- 登录 MySQL:
mysql -u root -p,然后执行:CREATE USER 'devuser'@'%' IDENTIFIED WITH mysql_native_password BY 'your_strong_password';
- 再授权:
GRANT ALL PRIVILEGES ON *.* TO 'devuser'@'%' WITH GRANT OPTION;
- 刷新权限:
FLUSH PRIVILEGES; - 注意:
'%'表示任意 IP,生产环境建议写具体 IP 段如'192.168.1.%',避免暴露全网
ufw / firewalld 必须放行 3306 端口,但别误开 MySQL 的 socket 文件权限
即使 MySQL 监听在 0.0.0.0:3306、用户也建好了,Linux 防火墙仍可能拦截连接请求。不过要注意:这不是“打开所有端口”的理由,更不该为了省事把 /var/run/mysqld/mysqld.sock 权限设成 777——那会破坏本地 socket 认证,反而让 mysql -u root 本地登录失败。
性能/兼容性影响:ufw 默认 deny 所有入站,firewalld 默认 zone 是 public,都不包含 3306。不配置,连接超时;配错,本地 CLI 反而报 Can't connect to local MySQL server through socket。
- Ubuntu(ufw):
sudo ufw allow 3306,然后sudo ufw status确认规则已生效 - CentOS(firewalld):
sudo firewall-cmd --permanent --add-port=3306/tcp,再sudo firewall-cmd --reload - 验证端口是否可达:
telnet 服务器IP 3306(若无 telnet,用nc -zv 服务器IP 3306)
客户端连接时指定 --protocol=tcp,绕过本地 socket 自动降级逻辑
有些客户端(比如某些版本的 MySQL CLI 或脚本里用 mysql_connect())在目标 IP 是本机或 127.0.0.1 时,会自动尝试用 Unix socket 连接,而不是 TCP。这时候即使你改了 bind-address 和用户权限,它还是走本地 socket 路径,结果连上的是 root@localhost 上下文,权限不匹配就报错。
容易踩的坑:在服务器本机上测试远程连接,用 mysql -h 127.0.0.1 -u devuser -p 却连不上,以为配置失败,其实只是协议选错了。
- 强制走 TCP:
mysql -h 127.0.0.1 -u devuser -p --protocol=tcp - 应用代码中也要显式指定 host 为 IP(而非
localhost),因为很多驱动对localhost有 socket 特殊处理 - PHP PDO 示例:
$pdo = new PDO('mysql:host=192.168.1.100;port=3306;dbname=test', $user, $pass);,host 不能写localhost
最常被忽略的是用户 host 段和 bind-address 的配合关系——bind-address = 0.0.0.0 只解决“能不能收包”,'user'@'%' 解决“收了包认不认识你”。两者漏一,远程连接就卡在不同阶段,错误信息还长得不一样,容易来回试错浪费时间。










