FEATURED · 精选文章

MySQL远程连接报错1130:Host not allowed的解决与加固

发布时间 / 2026/9/7 19:34:03
来源 / 创域科博编辑部
栏目 / 资讯中心
MySQL远程连接报错1130:Host not allowed的解决与加固 我前阵子帮朋友排查一个线上小项目数据库在 Ubuntu 服务器上跑得好好的本地连一点问题没有结果换台电脑用 Navicat 一连直接甩回来一个1130 - Host x.x.x.x is not allowed to connect to this MySQL server。当时他截图给我我一看就知道是怎么回事——这根本不是密码错了也不是端口不通纯粹是 MySQL 默认只让本机访问压根没给远程 IP 开门。这个报错几乎每个用 MySQL 的人都会撞上尤其是刚把数据库部署到服务器、准备从本地连过去的时候。今天我就把这个问题的完整处理流程拆开揉碎讲清楚从最底层的权限机制说到具体的排查命令最后再把安全加固的操作也一并给你。不管你是刚入门的开发新手还是偶尔客串运维的后端照着我这套思路走基本十分钟之内能解决。1. 问题定位先搞懂“拒绝访问”拒绝的到底是什么很多人在这一步就卡住了把密码反复改了好几遍防火墙也关了结果还是连不上。我建议你先把心态放稳Host is not allowed to connect这个报错的含义其实非常明确MySQL 知道你的密码是对的但因为你的来源 IP 不在允许列表里所以在认证阶段就直接把你拒了。1.1 一条记录看懂 MySQL 的用户权限模型MySQL 里的用户从来不是单纯靠“用户名”区分的它的完整定义是“用户名 来源 Host”。你可以在本机跑一下这条 SQLSELECT user, host, plugin, authentication_string FROM mysql.user;输出结果里你会看到类似这样的记录---------------------------------------------------- | user | host | plugin | ---------------------------------------------------- | root | localhost | caching_sha2_password | | root | % | caching_sha2_password | | debian-sys-maint | localhost | caching_sha2_password | ----------------------------------------------------userroot这行如果你只看前半截会觉得“同一个用户怎么会有两条记录”其实它们是完全独立的两个登录身份。rootlocalhost只管本机通过 socket 或 127.0.0.1 连进来的请求root%才是允许从任何 IP 远程连进来的身份。MySQL 在认证时会同时匹配用户名和来源地址只要有一条对不上就会直接拒绝。1.2 为什么默认只有 localhostMySQL 安装后默认只创建rootlocalhost再加上一堆mysql.syslocalhost之类的系统账号这种做法是故意的。数据库不像普通 Web 服务它存的是最核心的数据资产默认只允许本机访问可以在很大程度上减少暴露面。很多新手不理解这个设计觉得“我密码都设了怎么还不让连”其实这就是数据库最基本的访问控制逻辑——你需要明确告诉它“我允许谁来连”而不是“我不允许谁来连”。1.3 检查你当前到底是哪种拒绝远程访问被拒其实分好几种情况你要先通过报错特征定位自己是哪一种报错信息含义原因定位1130 - Host x.x.x.x is not allowed to connect to this MySQL serverHost 不在允许列表user 表的 host 字段不匹配1045 - Access denied for user rootx.x.x.x (using password: YES)用户名或密码错误认证失败可能是密码错误或插件不兼容2003 - Cant connect to MySQL server on x.x.x.x (10060)网络不通防火墙或端口未开放1040 - Too many connections连接数超限max_connections 参数过小你遇到的是1130那核心战场就在 MySQL 的 user 表。接下来要做的就是两件事一是创建一个允许远程登录的账号或者改现有账号的 host二是刷新授权让配置生效。2. 修改 user 表 host 权限核心操作与完整流程这个环节是整个问题的主战场。我见过网上很多教程让你直接UPDATE mysql.user SET host% WHERE userroot;确实能解决问题但我不建议你上来就这么干尤其是线上环境。我更推荐用CREATE USER或GRANT的方式单独建一个远程账号这样权限更可控也更好撤销。2.1 先备份再动手在改任何权限之前先给 MySQL 的授权表做个快照。这一步很多人会跳过但等你误删了生产库的 root 账号再回来补的时候就知道有多痛了。# 在服务器本机执行用系统 root 或 MySQL root 登录 mysqldump -u root -p mysql user ~/mysql_user_backup.sql这个命令只备份mysql库里的user表不涉及你的业务数据执行速度很快。备份文件里包含所有用户的 host、plugin、authentication_string 信息万一改坏了还能恢复。2.2 两种方案对比改 root 还是新建账号方案一直接修改 root 的 hostUSE mysql; UPDATE user SET host % WHERE user root AND host localhost; FLUSH PRIVILEGES;这个方案的问题在于第一rootlocalhost被覆盖后本机通过 socket 登录的身份就变成了root%在某些特殊配置下比如skip_name_resolve开启时反而可能连本机都登不进去第二root 拥有全部权限一旦远程账号密码泄露整个数据库完全暴露。我只有在临时测试环境才会这么干。方案二推荐新建独立远程账号-- 创建一个专门用于远程连接的账号赋予常见业务权限 CREATE USER remote_user% IDENTIFIED BY YourStrongPassword123!; GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, INDEX ON your_database.* TO remote_user%; FLUSH PRIVILEGES;如果你连的是 MySQL 8.0 以上版本CREATE USER之后还需要执行ALTER USER来指定认证插件吗不需要默认就是caching_sha2_password。但是这里有一个很常见的坑如果你的客户端是 Python 的mysqlclient库或者老版本的 Navicat12 以下对caching_sha2_password支持不好连的时候会报Authentication plugin caching_sha2_password cannot be loaded。这个时候你需要在创建用户时显式指定CREATE USER remote_user% IDENTIFIED WITH mysql_native_password BY YourStrongPassword123!;MySQL 8.0 仍然支持mysql_native_password插件只是默认不再启用你可以按需手动指定。对于 5.7 及更早版本默认就是mysql_native_password不需要关心这个参数。2.3 如果必须保留 root 远程访问该怎么做如果你确实有场景需要 root 远程登录比如用一些可视化运维工具管理多台实例那我建议你不要直接改rootlocalhost而是复制一条记录出来CREATE USER root% IDENTIFIED BY YourVeryStrongPassword; GRANT ALL PRIVILEGES ON *.* TO root% WITH GRANT OPTION; FLUSH PRIVILEGES;这样rootlocalhost和root%是两条独立记录本机登录不受影响同时也能远程访问。之后想收回远程权限直接DROP USER root%;就行不影响本机使用。2.4 host 字段的更多玩法精确 IP 和网段%表示匹配所有 IP但实际生产环境里我更建议精确限制来源地址。MySQL 的 host 字段支持多种匹配模式host 写法匹配范围使用场景%所有 IP测试环境、完全开放192.168.1.100单个 IP固定办公 IP、指定应用服务器192.168.1.%网段内网固定网段db-client.example.com主机名反向解析匹配域名比如你只想允许办公网络的某个网段连CREATE USER report_user192.168.1.% IDENTIFIED BY Report2024!; GRANT SELECT ON report_db.* TO report_user192.168.1.%;这样即使密码泄露外部 IP 也无法利用这个账号连进来等于多了一层网络层面的保险。还有一些场景下你的应用服务器 IP 是固定的那就直接绑 IP 而不是给%这是我在生产环境最常用的做法。3. 实操验证从改完权限到真正连通的全过程改完 user 表不等于万事大吉中间隔着一堆检查环节。我这里分享一套我自己的标准验证流程每一步都有明确目的照着做一遍基本能确认问题到底出在哪个层面。3.1 服务器本机先验证 MySQL 状态远程连不上之前先确认 MySQL 服务本身是健康的systemctl status mysql # 或者 service mysql status看到active (running)就代表服务正常。然后再确认下监听端口是否开启netstat -tlnp | grep 3306正常的输出应该是类似这样tcp6 0 0 :::3306 :::* LISTEN 1234/mysqld这里有一个关键细节如果你看到的是127.0.0.1:3306而不是:::3306或者0.0.0.0:3306那就说明 MySQL 只监听了本机回环地址这种情况下即使你改完 user 表远程照样连不上。这个是 MySQL 配置文件里的bind-address参数控制的后面我会专门讲。3.2 客户端做网络连通性测试在你要发起远程连接的电脑上执行# Linux/Mac terminal 或 Windows CMD telnet 你的服务器IP 3306或者用更通用的nc -zv 你的服务器IP 3306如果端口通telnet会进入一个空白界面黑窗口这时候输入任意字符回车会看到 MySQL 返回一个类似5.7.42-0ubuntu0.18.04.1-log的版本号字符串。看到版本号说明 TCP 连接已经打到了 MySQL接下来报的任何错误都是数据库层面的认证问题。如果telnet直接超时或者拒绝连接那问题出在防火墙、安全组或者 bind-address 上跟 user 表没关系。3.3 用命令行客户端测试远程连接网络层通了之后我用命令行做最后的认证测试mysql -h 你的服务器IP -P 3306 -u remote_user -p输入密码后如果能正常进入mysql提示符恭喜你权限层面已经全部打通。我习惯再执行一条确认当前登录身份SELECT CURRENT_USER();这步会返回类似于remote_user你的IP的结果我从这里能确认 MySQL 到底把你匹配到了哪条 user 表记录对排查非常有帮助。比如说你建了remote_user%但连接时却匹配到另一条remote_userlocalhost返回结果里会直接体现出来。3.4 别忘了在可视化工具里测试命令行走通之后再打开 Navicat 或者 DBeaver 连接。如果你用的是 Navicat连接时在“SSH 通道”那个 Tab 里不要勾选任何东西直接在“常规”Tab 填主机、端口、用户名、密码即可。如果命令行能连上但 Navicat 连不上99% 是认证插件兼容性问题回 2.2 小节去把账号改成mysql_native_password再试。4. 扩展排查即使改了 user 表还是连不上的常见原因我在帮别人处理这个问题时发现很多时候用户改了host %之后还是连不上然后就懵了。这种情况通常不是 user 表的问题而是其他几个环节没跟上。我把这些年踩过的一些坑集中整理在这里。4.1 MySQL 只监听了 127.0.0.1这是改完权限仍然连不上的头号原因。MySQL 默认配置文件里有一行bind-address 127.0.0.1或者是 MySQL 8.0 默认安装时没有这行但skip-networking开着。你可以这样确认SHOW VARIABLES LIKE bind_address; SHOW VARIABLES LIKE skip_networking;bind_address如果是127.0.0.1那远程连接根本到不了 MySQL 这个进程。修改方式是在配置文件里改掉[mysqld] bind-address 0.0.0.0或者更安全一点只绑定你服务器的内网 IP如果有独立内网网卡的话[mysqld] bind-address 192.168.1.10改完记得重启systemctl restart mysql注意bind-address 0.0.0.0代表监听所有网卡如果你有多块网卡且只想暴露其中一块可以指定具体 IP不用分号分隔因为 MySQL 8.0 之前的版本不支持多地址绑定。4.2 防火墙和安全组没放行 3306Ubuntu 的 UFW、CentOS 的 firewalld、云服务器厂商的安全组三层都可能拦截 TCP 3306 端口。我自己在云服务器上犯过最蠢的错误本地 UFW 放行了 3306结果云控制台的安全组入方向规则没加白折腾了半天。Ubuntu 下放行端口sudo ufw allow 3306/tcp sudo ufw reloadCentOS 7 下放行端口sudo firewall-cmd --permanent --add-port3306/tcp sudo firewall-cmd --reload云平台的安全组规则各厂商面板不一样但原理都是添加一条“入方向、TCP、端口 3306、来源 0.0.0.0/0”或者限定你的办公网 IP 的规则。这里再次提醒放行端口时最好限定来源 IP而不是全放通。4.3 MySQL 8.0 的 caching_sha2_password 坑这个问题前面提过这里我多写几个排查要点。caching_sha2_password是 MySQL 8.0 的默认认证插件比老旧的mysql_native_password安全得多但兼容性没跟上。老版本的客户端、ODBC 驱动、JDBC 驱动在连接时可能报Authentication plugin caching_sha2_password cannot be loadedUnable to load authentication plugin caching_sha2_passwordPublic Key Retrieval is not allowed第三种报错通常出现在 Java 连接 MySQL 8.0 的场景解决方式是在 JDBC URL 里加参数allowPublicKeyRetrievaltrueuseSSLfalse。如果你不想每次都用这个参数那就直接把账号切成mysql_native_passwordALTER USER remote_user% IDENTIFIED WITH mysql_native_password BY YourNewPassword;这个操作只是改认证插件和密码不会影响已有数据。我一般是在开发环境图省事才这么干生产环境会尽量升级客户端驱动保持caching_sha2_password。4.4 skip-name-resolve 导致 host 匹配异常如果你的 MySQL 配置了skip-name-resolve那么 user 表里 host 字段就只能写 IP 或%不能写域名。这个配置在默认情况下是关闭的但有些安全加固指南会建议开启。开启后MySQL 不再对客户端 IP 做反向 DNS 解析如果你在 host 字段里写了localhost反而可能出现连接被拒的问题。排查方法很简单SHOW VARIABLES LIKE skip_name_resolve;如果结果是ON而你的账号 host 写的是localhost建议改成127.0.0.1或%。4.5 权限改完必须刷新授权表我见过有人执行了UPDATE之后没有加FLUSH PRIVILEGES;结果怎么重启都没用。原因是 MySQL 的权限表是带缓存的直接改表不会自动生效必须手动刷新FLUSH PRIVILEGES;如果你用的是CREATE USER或GRANT语句来修改权限MySQL 会自动刷新授权表不需要手动执行。但问题是你可能混合使用了UPDATE和GRANT所以我习惯在任何修改之后都执行一次FLUSH PRIVILEGES;确保万无一失。5. 安全加固远程访问权限不是越开放越好说实话我见过太多人解决了远程访问问题之后就直接把root%晾在那里密码还设成了弱口令这等于把数据库裸奔在公网上。下面这套加固操作我建议在你能远程连上之后立刻做一遍。5.1 不要把 root 暴露在远程如果你只是为了日常开发方便完全可以用一个最小权限账号。先看看你的库和表确定业务账号真正需要哪些权限-- 示例某个需要操作订单库所有表的账号 CREATE USER order_app192.168.1.% IDENTIFIED BY OrderApp_StrongPwd_2024; GRANT SELECT, INSERT, UPDATE, DELETE ON order_db.* TO order_app192.168.1.%;只有像 DBA 或自动化运维工具才需要ALL PRIVILEGES。业务账号永远遵循最小权限原则。GRANT权限按实际需要来比如数据迁移工具需要SELECT和FILE报表工具只需要SELECT。5.2 定期清理不再使用的账号你可以用这个 SQL 找出超过 180 天没登录过的用户SELECT user, host, last_attempt_time FROM mysql.user;MySQL 8.0 里 user 表有last_attempt_time、last_success_time字段5.7 里可能没有可以参考清理。清理命令DROP USER old_account%;另外如果你有对外开放但只在特殊时段使用的账号可以配合 event scheduler 做定时锁定这个玩法比较进阶我在这里提一句就不展开了。5.3 用简单内核参数限制连接来源和频率除了数据库层面的 host 限制你还可以在操作系统层面用iptables或nftables做限制。比如只允许办公室 IP 访问 3306 端口sudo iptables -A INPUT -p tcp --dport 3306 -s 你的办公网段 -j ACCEPT sudo iptables -A INPUT -p tcp --dport 3306 -j DROP这种做法的好处是即使 MySQL 账号密码泄露外部攻击者也无法从网络层面触达数据库端口。同时设置连接数限制sudo iptables -A INPUT -p tcp --dport 3306 -m connlimit --connlimit-above 10 --connlimit-mask 32 -j REJECT这个命令限制单个来源 IP 最多保持 10 个 TCP 连接超过即拒绝可以在一定程度上缓解暴力破解的连接洪峰。5.4 从日志中识别异常远程访问MySQL 的通用查询日志和错误日志都能帮你发现异常访问。开启通用查询日志SET GLOBAL general_log ON; SET GLOBAL log_output TABLE;开启后可以查mysql.general_log表SELECT * FROM mysql.general_log WHERE command_type Connect ORDER BY event_time DESC LIMIT 50;注意生产环境不建议长时间开启通用日志因为写入量很大。通常在排查时开 10 分钟到半小时就够了排查完立即关闭SET GLOBAL general_log OFF;对于连接失败的记录查看 MySQL 错误日志通常路径在/var/log/mysql/error.log或/var/log/mysqld.log里面能看到类似这种信息Access denied for user root218.108.x.x (using password: YES)这类日志是排查暴力破解和异常扫描的第一手线索。我最近看错误日志时就发现某个 IP 连续尝试了几百次root密码于是直接iptables DROP了这个 IP瞬间安静了。5.5 进阶用 ProxySQL 或防火墙白名单做统一入口如果你的架构里有多个应用服务器需要访问同一套 MySQL与其开放一堆 IP不如在前面架一个 ProxySQL 统一代理。ProxySQL 把真实 MySQL 的端口在公网完全隐藏应用只连 ProxySQL由它转发到后端的 MySQL。这样你可以在 ProxySQL 层做更细粒度的账户和流量控制MySQL 本身可以只绑定内网 IP。这种方式适合稍微复杂一点的架构单机项目用不上但知道有这条思路对以后扩展会有帮助。6. 常见问题速查按报错信息快速找到解决方向我在实际帮人排查的过程中总结了下面这张表。你连不上 MySQL 的时候先对着报错信息看一眼再定位到对应章节去处理能省很多时间。报错信息核心原因解决方向Host x.x.x.x is not allowed to connectuser 表 host 字段限制修改 host 或新建远程账号Access denied for user rootx.x.x.x用户名或密码错误 / 插件不兼容检查密码确认认证插件Cant connect to MySQL server on x.x.x.x (10060)TCP 不通防火墙、安全组、bind-addressAuthentication plugin caching_sha2_password cannot be loaded客户端太旧不支持 MySQL 8 默认插件升级客户端或用 mysql_native_passwordPublic Key Retrieval is not allowed连接 MySQL 8 时安全参数问题JDBC URL 加 allowPublicKeyRetrievaltrueLost connection to MySQL server at reading initial communication packet协议不匹配或网络不稳检查服务端版本和客户端兼容性调整 net_read_timeout、net_write_timeout这张表不能覆盖所有场景但能解决我在实际支持中遇到的大概 80% 的远程连接问题。剩下那 20%基本要靠SHOW VARIABLES、SHOW STATUS和错误日志一步步排查。7. 我的一点个人经验每次改权限之前永远想清楚这三件事先问自己这个账号真的要开放到%吗还是精确到一个 IP 就够了。其次这个账号真的需要 root 级权限吗还是只给业务相关库的增删改查就行。最后如果这个账号被攻破了损失范围有多大这三个问题想清楚再动手改你的数据库安全等级会立刻上升一个台阶。我自己的习惯是先把最小权限账号建好再用命令行客户端测试测试通过后再去调防火墙和安全组最后才在可视化工具里连。每一步都验证通过后才会认为这个“远程访问被拒绝”的问题真正闭环了而不是改完 host 就撒手不管。MySQL 的权限体系表面上是一张 user 表但背后是一整套认证和授权逻辑。你理解了“用户名 Host”这个组合才是真正身份标识之后以后看到任何类似权限报错脑子里就会自动有排查路径了。希望这篇文章能帮你跨过这个门槛少走一些我当时走过的弯路。
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻