• 记一次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

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

  • 相关阅读:
    关于ajaxfileupload的使用方法以及一些问题
    vs里根据json快速创建对应类的方法
    20175227张雪莹 2018-2019-2 《Java程序设计》第四周学习总结
    关于:socket阻塞、非阻塞,同步、异步、I/O模型
    推挽输出理解
    使用指针做形参来解决函数的副本机制
    c语言副本机制
    开关电源电容选择
    MFC入门示例之水平滚动条和垂直滚动条(CScroll Bar)
    MFC入门示例之组合框(CComboBox)、列表框(CListBox)
  • 原文地址:https://www.cnblogs.com/chyingp/p/mysql-access-denied-because-of-anonymous-user.html
Copyright © 2020-2023  润新知