远程连接被拒绝主因是mysqld未监听外网地址,需将bind-address设为0.0.0.0并重启服务,再通过ss -tuln | grep :3306确认监听状态为*:3306,同时检查用户host权限、防火墙、云安全组及mysql 8.0认证插件兼容性。

远程连接被拒绝,90%的情况不是密码错、也不是服务没起,而是mysqld根本没监听你的IP——它只守着127.0.0.1:3306,外部请求连socket都没机会建立。
确认mysqld到底监听了哪些地址
别信systemctl status mysql显示“active”,得看它实际注册了哪个socket:
- Linux执行:
ss -tuln | grep :3306,如果只看到127.0.0.1:3306或::1:3306,说明它拒绝所有远程TCP连接 - 理想输出是
*:3306(IPv4)或[::]:3306(IPv6),代表监听所有接口 - 完全没输出?说明
mysqld没启动,或配置了skip-networking = ON
改bind-address前先看配置文件位置和写法
MySQL读取的配置文件不唯一,常见路径有/etc/my.cnf、/etc/mysql/mysql.conf.d/mysqld.cnf、/etc/mysql/my.cnf,优先检查最后加载的那个(可用mysql --help | grep "Default options"确认):
- 在
[mysqld]段下找bind-address,必须显式设为0.0.0.0或服务器真实内网IP(如192.168.1.100) -
bind-address = localhost、bind-address = 127.0.0.1、空值、注释掉、或带多余空格(如bind-address= 127.0.0.1)都会导致监听失败 - 顺手确认
skip-networking是否被注释(前面有#),否则网络功能直接关闭 - 改完必须
systemctl restart mysql(Ubuntu/Debian)或systemctl restart mysqld(CentOS/RHEL),reload不生效
用户权限不是“开个root就行”,而是'user'@'host'要精确匹配
MySQL把'root'@'localhost'和'root'@'%'当成两个完全不同的账号,远程连接时匹配的是后者:
- 执行
SELECT host, user FROM mysql.user;,如果root行的host是localhost,远程必然报ERROR 1130 - MySQL 8.0起,不能再用
GRANT ... IDENTIFIED BY一步建用户+授权,必须拆成两步:CREATE USER 'root'@'%' IDENTIFIED BY 'your_strong_password';GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION; - 或者更安全的做法:直接更新已有记录(仅限调试):
UPDATE mysql.user SET Host = '%' WHERE User = 'root' AND Host = 'localhost';FLUSH PRIVILEGES; - 生产环境强烈建议不用
%,改用具体子网如'192.168.1.%',并创建专用账号而非开放root
防火墙和云安全组是最后一道关卡
即使mysqld监听了0.0.0.0:3306、用户权限也配对了,宿主机或云平台的防火墙仍可能丢弃入站包:
- Linux本地防火墙:
firewall-cmd --query-port=3306/tcp(firewalld)或ufw status(UFW),没放行就加规则并--reload - 云服务器(阿里云/腾讯云等):必须在控制台“安全组”里单独添加入方向规则,允许
3306/tcp,来源IP不能写成0.0.0.0/0除非真需要全网访问 - VirtualBox等虚拟机:检查NAT端口转发是否启用,宿主机
telnet 127.0.0.1 33306能通,不代表虚拟机内部3306已暴露
最容易被忽略的点:MySQL 8.0默认启用caching_sha2_password认证插件,某些旧客户端(如Navicat老版本)不兼容,会表现为“连接成功但立刻断开”或“Access denied”——这时得在创建用户时显式指定auth_plugin,或改用mysql_native_password插件。











