MySQL错误:用户'a'@'localhost'的访问被拒绝(使用密码:是)

Jus*_*ner 23 mysql authentication

我使用 root 帐户创建的帐户'a'@'%'。但是我在指定host参数时无法使用该帐户连接到MySQL服务器。我可以不带-h参数成功连接。请看下面的文字记录。我希望有人能帮我解释一下。谢谢。

mysql> grant all on *.* to 'a'@'%' identified by a;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'a' at line 1
mysql> grant all on *.* to 'a'@'%' identified by 'a';
Query OK, 0 rows affected (0.00 sec)

mysql> show grants for 'a'@'%';
+-----------------------------------------------------------------------------------------------------------+
| Grants for a@%                                                                                            |
+-----------------------------------------------------------------------------------------------------------+
| GRANT ALL PRIVILEGES ON *.* TO 'a'@'%' IDENTIFIED BY PASSWORD '*667F407DE7C6AD07358FA38DAED7828A72014B4E' |
+-----------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> exit
Bye

[root@localhost ~]# mysql -h localhost -u a -p
Enter password: 
ERROR 1045 (28000): Access denied for user 'a'@'localhost' (using password: YES)
[root@localhost ~]# mysql -h 127.0.0.1 -u a -p
Enter password: 
ERROR 1045 (28000): Access denied for user 'a'@'localhost' (using password: YES)
[root@localhost ~]# mysql -u a -p
Enter password: 
ERROR 1045 (28000): Access denied for user 'a'@'localhost' (using password: YES)
[root@localhost ~]# mysql -u a
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 20
Server version: 5.5.17 MySQL Community Server (GPL)

Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>
mysql> status
--------------
mysql  Ver 14.14 Distrib 5.5.17, for Linux (x86_64) using readline 5.1

Connection id:      20
Current database:   
Current user:       a@localhost
SSL:            Not in use
Current pager:      stdout
Using outfile:      ''
Using delimiter:    ;
Server version:     5.5.17 MySQL Community Server (GPL)
Protocol version:   10
Connection:     Localhost via UNIX socket
Server characterset:    utf8
Db     characterset:    utf8
Client characterset:    utf8
Conn.  characterset:    utf8
UNIX socket:        /var/lib/mysql/mysql.sock
Uptime:         15 days 15 hours 20 min 18 sec

Threads: 1  Questions: 40  Slow queries: 0  Opens: 41  Flush tables: 1  Open tables: 4  Queries per second avg: 0.000
--------------

mysql> 
Run Code Online (Sandbox Code Playgroud)

编辑:

是的,MySQL 正在侦听端口 3306。

[root@localhost ~]# nmap localhost

Starting Nmap 4.11 ( http://www.insecure.org/nmap/ ) at 2012-01-18 07:35 CST
Interesting ports on localhost.localdomain (127.0.0.1):
Not shown: 1674 closed ports
PORT     STATE SERVICE
22/tcp   open  ssh
25/tcp   open  smtp
111/tcp  open  rpcbind
631/tcp  open  ipp
840/tcp  open  unknown
3306/tcp open  mysql

Nmap finished: 1 IP address (1 host up) scanned in 0.064 seconds
[root@localhost ~]# 
Run Code Online (Sandbox Code Playgroud)

Rol*_*DBA 28

??????????这里有一个快速而肮脏的方法,用于检查 MySQL 如何执行成功的身份验证。

请运行此查询:

SELECT USER(),CURRENT_USER();
Run Code Online (Sandbox Code Playgroud)

USER()报告您如何尝试在 mysqld 中进行身份验证

CURRENT_USER()报告您如何被 mysqld 允许进行身份验证

有时,USER()CURRENT_USER()是不同的。那是因为 mysql 身份验证遵循特定协议。

根据MySQL 5.0 认证学习指南

在此处输入图片说明

第 486,487 页对 mysql 的身份验证算法进行了说明:

客户端访问控制有两个阶段:

在第一阶段,客户端尝试连接,服务器接受或拒绝连接。为了尝试成功,用户表中的某些条目必须与客户端连接的主机、用户名和密码相匹配。

在第二阶段(只有当客户端已经成功连接时才会发生),服务器检查它从客户端收到的每个查询,以查看客户端是否有足够的权限来执行它。

服务器根据客户端连接的主机和客户端提供的用户将客户端与授权表中的条目进行匹配。但是,可能有多个记录匹配:

授权表中的主机值可以指定为模式包含通配符值。如果授权表包含来自myhost.example.com%.example.com%.com和 的条目%,则所有这些条目 都与从 连接的客户端匹配myhost.example.com

授权表条目中的用户值不允许使用模式,但可以将用户名作为空字符串提供以指定匿名用户。空字符串匹配任何用户名,因此有效地充当通配符。

当多个用户表记录中的 Host 和 User 值与客户端匹配时,服务器必须决定使用哪一个。它通过首先对具有最具体 Host 和 User 列值的记录进行排序,然后选择排序列表中最先出现的匹配记录来实现这一点,排序过程如下:

在主机列,文字值,如localhost127.0.0.1myhost.example.com排序提前,如值%.example.com 是在他们模式字符。模式值根据它们的具体程度进行排序。例如,%.example.com%.com更具体,比 更具体%

在用户列中,非空白用户名排在空白用户名之前。也就是说,非匿名用户排在匿名用户之前。

服务器在启动时执行此排序。它将授权表读入内存,对它们进行排序,并使用内存中的副本进行访问控制。

从这个描述中,你不需要担心 mysql.user 表的顺序,因为有一个授权表的内存副本,它按照前面提到的方式排序。

关于您登录的方式,仅mysql -u a起作用。返回并再次登录并运行这些命令

SELECT USER(),CURRENT_USER();
SELECT user,host,password FROM mysql.user;
Run Code Online (Sandbox Code Playgroud)

确保

  • 每个用户都有一个密码。
  • 没有匿名用户(当用户为空时)

这只是一个猜测,但我怀疑mysql -u a通过 localhost 连接,因为当未指定连接协议时,默认是通过套接字文件连接。可能存在mysql.user允许匿名本地主机连接的条目。

运行此查询:

SELECT user,host,password FROM mysql.user WHERE user='' AND host='localhost';
Run Code Online (Sandbox Code Playgroud)

如果您在没有密码的情况下返回一行,这完全解释了为什么mysq -u a有效。

更新 2012-01-19 11:12 EDT

Craig Efrein提出了一个有趣的问题:如果 mysql.user 表中存在两个相同的用户名,一个有密码,一个没有,这是否意味着 MySQL 在不使用密码时拒绝身份验证?

这个问题是关于 MySQL 用户身份验证的一个很好的提示。

请注意mysql.user 的主键是host,user。没有其他索引。这允许用户名多次出现。每次出现都可以有不同的密码或没有密码。这允许用户 'dbuser' 无需密码即可在本地登录 (dbuser@localhost),并且同一用户从给定网络块 (dbuser@'10.1.2.20') 内的另一台服务器登录,使用类似 'pass1' 的密码,该用户即可登录使用“pass2”之类的远程密码从任何地方(dbuser@'%')远程访问。

鉴于 MySQL 使用的身份验证算法,对存在或不存在密码的用户没有任何限制。

这就是为什么MySQL 5.0 认证学习指南在第 498 页第 6 段的要点中指出如何清理身份验证过程:

在 Unix 上,MySQL 带有一个 mysql_secure_installation 脚本,它可以在您的安装上执行几个有用的与安全相关的操作。该脚本具有以下功能:

  • 为 root 帐户设置密码
  • 删除任何可远程访问的 root 帐户。
  • 删除匿名用户帐户。这提高了安全性,因为它可以防止任何人以 root 身份从远程主机连接到 MySQL 服务器的可能性。结果是,任何想要以 root 身份连接的人都必须首先能够登录服务器主机,这为抵御攻击提供了额外的屏障。
  • 删除测试数据库(如果删除匿名帐户,您可能还想删除他们有权访问的测试数据库)。

  • Rolando,如果 mysql.user 表中存在两个相同的用户名,一个有密码,一个没有,这是否意味着 MySQL 在不使用密码时拒绝身份验证? (3认同)

atx*_*dba 6

“%”主机通配符与“localhost”不匹配。默认情况下,mysql 客户端将尝试通过套接字而不是 tcp(通常是 /var/lib/mysql/mysql.sock 这样的地方)进行连接。

您可以将您的授权更改为 'a'@'localhost',或者强制客户端通过 TCP 堆栈进行操作,例如:

mysql -u a -p --protocol=TCP
Run Code Online (Sandbox Code Playgroud)