mysql远程访问必须同时配置bind-address、用户host权限和防火墙/安全组,三者缺一不可;bind-address决定监听地址,create user需显式指定ip而非%以实现精准控制,flush privileges确保权限生效,且须关闭skip_name_resolve避免dns反查失败。

不能只靠 bind-address 或配置文件“开关”实现——必须组合用户权限 + 系统防火墙 + MySQL监听配置,三者缺一不可。
CREATE USER 时必须显式指定公网IP
MySQL 没有全局白名单机制,host 字段就是访问控制的唯一入口。用 % 或 localhost 都会绕过你的限制目标。
- 允许单个公网 IP(如
203.204.101.88)连接:CREATE USER 'app'@'203.204.101.88' IDENTIFIED BY 'strong_pass_2026';GRANT SELECT, INSERT ON mydb.* TO 'app'@'203.204.101.88'; - 禁止通配符用户残留:
DROP USER 'app'@'%';(否则优先级更低的规则会被忽略) -
'app'@'203.204.101.88'和'app'@'203.204.101.%'是两个独立账户,后者匹配整个 C 类网段,慎用 - 执行
FLUSH PRIVILEGES;后权限才生效,但多数现代 MySQL 版本在GRANT后自动刷新,手动执行更保险
bind-address 必须设为 0.0.0.0 或具体公网IP
bind-address 控制 MySQL 进程监听哪个地址,不是访问控制开关,但它决定“能不能被连上”。设成 127.0.0.1 或内网IP,公网IP根本连不到端口。
- 编辑
/etc/mysql/mysql.conf.d/mysqld.cnf(Ubuntu)或/etc/my.cnf(CentOS) - 确认
[mysqld]下有:bind-address = 0.0.0.0(监听所有接口)
或更安全的:bind-address = 192.0.2.100(填你服务器实际绑定的公网IP,需确保该IP已配置在网卡上) - 务必注释掉
skip-networking,否则 TCP 连接被彻底禁用 - 改完重启服务:
sudo systemctl restart mysql(Ubuntu)或sudo systemctl restart mysqld(CentOS)
云服务器必须开防火墙放行 3306(且注意安全组)
即使 MySQL 监听 0.0.0.0 并授权了用户,系统防火墙和云平台安全组仍会拦截连接请求。两者都要配,且规则顺序影响结果。
- Linux 系统层(以
ufw为例):sudo ufw allow from 203.204.101.88 to any port 3306 - 若用
iptables:sudo iptables -A INPUT -s 203.204.101.88 -p tcp --dport 3306 -j ACCEPT - 云平台(阿里云/腾讯云/华为云等):必须在“安全组”里添加入方向规则,源 IP 填
203.204.101.88/32,协议端口填TCP:3306 - 注意:安全组规则优先级高于系统防火墙;如果安全组默认拒绝所有,系统防火墙再怎么开也没用
验证连接时别漏掉 DNS 和反向解析问题
MySQL 默认开启 skip_name_resolve = OFF,会尝试对客户端 IP 做反向 DNS 查询。若公网 IP 没有 PTR 记录,连接可能超时或失败,且错误日志不直观。
- 在
[mysqld]段中显式关闭:skip_name_resolve = ON - 重启 MySQL 后,
SHOW VARIABLES LIKE 'skip_name_resolve';应返回ON - 检查是否真生效:
SELECT USER(), CURRENT_USER();
前者显示客户端传来的用户名@主机名(可能含 DNS 名),后者显示权限系统匹配的user@host(应是app@203.204.101.88) - 如果
CURRENT_USER()显示的是app@%,说明你漏删了'app'@'%'用户,权限匹配走了通配符路径
真正卡住的地方往往不是某一步没做,而是多个环节的“默认行为”叠加:MySQL 默认只绑 127.0.0.1、云平台安全组默认拒绝所有、系统防火墙默认 deny、DNS 反查失败静默超时……每个都得单独验证,不能假设“配了用户就一定能连”。











