记一次MySQL数据库拒绝访问的解决过程

摘要:
问题背景使用Wordpress构建博客,数据库使用MySQL。您需要对MySQL帐户创建和客户端连接验证有一定的了解。当主机设置为%时,意味着可以从任何主机连接数据库。后来写道,由于存在匿名用户,本地连接数据库拒绝连接。这个问题很常见。很多人认为这是MySQL的设计缺陷,比如这里。一旦你了解了MySQL的认证逻辑,当你遇到类似的问题时,你就会有想法。此外,MySQL拒绝访问的原因很多,读者应该分析具体问题。

问题背景

用wordpress搭博客,数据库采用MySQL。为了调试方便,创建账户my_account ,允许它从任意主机访问数据库。

CREATE USER `my_account`@'%' IDENTIFIED BY 'my_password';

修改 wp-config.php 相应配置,注意 DB_HOST 设置为 127.0.0.1

define('DB_USER', 'my_account'); // 账号
define('DB_PASSWORD', 'my_password'); // 密码
define('DB_HOST', '127.0.0.1'); // 数据服务地址

部署到云服务器上,本地浏览器访问博客,提示数据库拒绝访问(本地连接远程数据没问题),以下为错误日志。

ERROR 1045 (28000): Access denied for user 'my_account'@'localhost' (using password: YES)`

简单排查后,解决了问题,这里记录下解决方案,以及出错的原因。

解决方案

1、方案一:删除 mysql.user表 中,Host字段为 localhost 的匿名账号(账户名为空)。
2、方案二:创建 my_account@localhost 账户,用于本地连接数据库。

笔者采用了方案 一。

首先,确认下 mysql.user 表中是否存在匿名账户。

MariaDB [(none)]> SELECT User, Host from mysql.user WHERE Host = 'localhost' AND User = '';
+------+-----------+
| User | Host      |
+------+-----------+
|      | localhost |
+------+-----------+
1 row in set (0.00 sec)

接着,删除相应匿名账户,再次尝试登陆,成功。

MariaDB [(none)]> DROP USER ''@'localhost';
Query OK, 0 rows affected (0.00 sec)

问题分析

为什么匿名账户会导致数据库连接失败?

需要对MySQL的账户创建、客户端连接校验有一定的了解。

创建MySQL账户

基础语法如下:

CREATE USER 账户名@主机 IDENTIFIED BY 密码;

注意点:(以下用 User 指代账户名,Host 指代 主机)

  1. Host 表示 允许账户从哪台主机访问数据库。主要用于做安全限制,可以是 主机名、IP地址、%(通配符);
  2. User 允许重复,只要 Host 是不同的就行。
  3. 当 Host 设置为 % 时,表示允许从任意主机连接数据库。

比如,存在两个xiaoming账户,一个允许从本机连接数据库,一个允许从 14.215.177.39 连接数据库。

MariaDB [(none)]> SELECT User, Host FROM mysql.user WHERE User = 'xiaoming';           
+---------+---------------+
| User    | Host          |
+---------+---------------+
| xiaoming | 14.215.177.39 |
| xiaoming | localhost     |
+---------+---------------+
2 rows in set (0.00 sec)

匿名账户

也就是 User 为空的账户,可以匹配任意用户名。如下指令创建了匿名账户。

CREATE USER ''@'localhost' IDENTIFIED BY 'pwd3';

身份校验

数据库服务器收到客户端连接,首先会进行身份校验,将 User、Host、Password 字段,跟 mysql.user 表里的记录进行比较,确认是否合法账户。

这里有个问题:如果 mysql.user表 中存在多条匹配记录,该以哪条记录为准?

答案是“优先级”。大致规则如下:

  1. 首先,检查 Host 字段。如果有多个 Host 符合条件,则选择匹配度最高的记录(IP地址 > 通配符%)。
  2. 其次,检查 User 字段。如果有多个 User 符合条件,则选择匹配度最高的记录。匿名用户可以匹配任何用户,因此匹配度最低。

优先级匹配例子

举例,假设本地数据库有如下两个账户(Password字段实际非明文)。

+------------+-----------+-----------+
| User       | Host      | Password  |
+------------+-----------+-----------+
| my_account | %         | 123       |
|            | localhost | 456       |
+------------+-----------+-----------+

运行如下命令,最终登录的账户,匹配的是 第2条 记录。(读者可自行尝试,输入密码123登录失败,输入456登录成功)

mysql -u my_account -p

为什么呢?回顾下匹配的优先级。

  1. 首先,检查 Host 字段。localhost、% 都符合要求。localhost 匹配度高于 %,因此匹配到第2条记录。
  2. 接着,检查 User 字段。第2条记录是匿名账户,可匹配任意User值,因此,第2条记录符合要求。

因此,虽然账户 my_account 的 Host字段 为%,但是在本地(数据库所在主机)连接数据库时,因为上述规则的存在,MySQL 会认为你是用匿名账户在登录。

my_account 跟匿名账户的密码是不同的,因此密码校验不通过,拒绝访问。

写在后面

因匿名用户存在,导致本地连接数据库拒绝连接,这个问题很常见,有不少人认为这是MySQL的设计缺陷,比如 这里

了解了MySQL的身份验证逻辑,遇到类似问题也就有思路了。关于%通配符,匹配优先级,上文并没有详细展开,感兴趣的读者可以自行查看官方文档。

另外,MySQL拒绝访问的原因有多种,读者应具体问题具体分析。

如有错漏,敬请指出。

相关链接

Host wildcard % which is said in docs that means "all hosts" excludes localhost

6.2.4 Access Control, Stage 1: Connection Verification

原文首发在笔者的个人博客,地址在这里

免责声明:文章转载自《记一次MySQL数据库拒绝访问的解决过程》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇干了3年程序员,我开窍了SSH 利用SecureCRT上传、下载文件(使用sz与rz命令)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

LaravelS

LaravelS LaravelS是一个胶水项目,用于快速集成Swoole到Laravel或Lumen,然后赋予它们更好的性能、更多可能性。Github 特性 内置Http/WebSocket服务器 多端口混合协议 协程 自定义进程 常驻内存 异步的事件监听 异步的任务队列 毫秒级定时任务 平滑Reload 修改代码后自动Reload 同时支持Lar...

MySQL 如何存储长度较大的varchar与blob

本文同时发表在https://github.com/zhangyachen/zhangyachen.github.io/issues/96 最近,在工作中遇到了MySQL中如何存储长度较长的字段类型问题,于是花了一周多的时间抽空学习了一下,并且记录下来。 MySQL大致的逻辑存储结构在这篇文章中有介绍,做为基本概念:InnoDB 逻辑存储结构 注:文中所...

使用nginx-prometheus-exporter 监控nginx

因为nginx 已经提供了stub_status 模块,一般我们可以基于此进行监控,目前官方提供了一个exporter 尽管有一些限制(web必须使用8080)。以下是一个简单的学习使用 环境准备 docker-compose 文件 注意使用了ranadeeppolavarapu 提供的nginx 镜像(很方便,可以学习各种nginx 插件的使用)...

PHP站内搜索:多关键字、加亮显示

一、SQL语句中的模糊查找       主要通过LIKE(不区分大小写)关键字实现模糊查找。LIKE条件一般用在指定搜索某字段的时候, 通过"%"或者" _" 通配符的作用实现模糊查找功能,通配符可以在字段前面也可以在后面或前后都有。只通过LIKE是无法实现模糊查找的,因此通配符的作用不可忽略。下面是三个实例:搜索以PHP开头:SELECT * FROM ...

SQL Server数据库级别触发器

  禁止修改表结构和加表 CREATE TRIGGER [Object_Change_Trigger_DDL] ON DATABASE FOR ALTER_TABLE,DROP_TABLE,CREATE_TABLE,CREATE_INDEX,ALTER_INDEX, DROP_INDEX AS DECLARE @EventData AS XML;...

批处理命令篇--配置免安装mysql

免安装版的mysql是进行软件绿色发布的绝佳助手,本文介绍一种使用批处理命令自动配置mysql的方法。 (1)建立三个文件,分别是:service install.bat,temp.txt,update.sql。 (2)在temp.txt文件中写入如下内容: set PathTemp= (3)在update.sql文件中写入如下内容: use mysql...