出此是用mysql,因为root权限过高,所以新建一用户appadmin,权限仅为要用到的数据库。创建语句如下:grant select,insert,update,delete on test.* to appadmin@"%" identified by "password";其中@“%”是可以在任何地址登录。 
创建后到mysql.user下查看,有该用户。但是使用mysql -u appadmin -ppassword 登录,提示无法登录:ERROR 1045 (28000): Access denied for user 'appadmin'@'localhost' (using password: YES) 
百思不得其解,遂google,其中有人说到“mysql.user 表中有另外一些记录产生了作用,最有可能的就是已经有一条''@localhost记录,就是用户名是空,主机字段是localhost的记录。” 影响了。查看该表果然有。 

mysql> select host,user,password from mysql.user;  

+-----------+------------------+-------------------------------------------+  

| host      | user             | password                                  |  

+-----------+------------------+-------------------------------------------+  

| localhost | root             | *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B |  

| mza       | root             | *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B |  

| 127.0.0.1 | root             | *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B |  

| localhost |                  |                                           |  

| mza       |                  |                                           |  

| localhost | debian-sys-maint | *19DF6BF8310D46D681AE072AB73ECEC99C018C19 |  

| %         | appadmin         | *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 |  

+-----------+------------------+-------------------------------------------+


7 rows in set (0.00 sec) 
但是删除那些为空(匿名)的用户后仍然无法登录。(可能是因为没有重启mysql)于是只好耐着性子看mysql参考手册。发现其中增加用户部分有这么一段话: 
其中两个账户有相同的用户名monty和密码some_pass。两个账户均为超级用户账户,具有完全的权限可以做任何事情。一个账户 ('monty'@'localhost')只用于从本机连接时。另一个账户('monty'@'%')可用于从其它主机连接。请注意monty的两个账户必须能从任何主机以monty连接。没有localhost账户,当monty从本机连接时,mysql_install_db创建的localhost的匿名用户账户将占先。结果是,monty将被视为匿名用户。原因是匿名用户账户的Host列值比'monty'@'%'账户更具体,这样在user表排序顺序中排在前面。 
这段话说的很清楚,因此执行 grant select,insert,update,delete on test.* to appadmin@"localhost" identified by "password"; 

退出后用appadmin登录,成功。



在安装完成MySQL后,我们通常添加拥有相应权限的普通用户用来访问数据库。在使用用户本地登录数据库的时候,经常会出现怎么登录也无法登录的情况,但是从其他的mysql客户端却可以登录。

[root@mysql01 ~]# mysql -userver -p123456
 ERROR 1045 (28000): Access denied for user 'server'@'localhost' (using password: YES)

本地登录失败;

[root@mysql02 ~]# mysql -h192.168.47.166 -userver -p123456
 Welcome to the MySQL monitor.  Commands end with ; or \g.
 Your MySQL connection id is 7
 Server version: 5.5.36-log Source distribution

远程登录成功;

一、登录后查看mysql.user表的情况

image

可以看到,我的数据库中有server用户和匿名用户localhost;
•server用户的密码是'server'
•匿名用户的密码为空

二、在本机用server用户登录,发现不用密码可以登录;

[root@mysql01 ~]# mysql -userver -p
 Enter password: 
 Welcome to the MySQL monitor.  Commands end with ; or \g.
 Your MySQL connection id is 3
 Server version: 5.5.36-log Source distribution Copyright (c) 2000, 2014, 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> SELECT USER(), CURRENT_USER();
 +--------------------------+-----------------------+
 | USER()                    | CURRENT_USER() |
 +-------------------------+------------------------+
 | server@localhost    | @localhost          |
 +-------------------------+-------------------------+
 1 row in set (0.00 sec)

登录成功了,使用USER()和CURRENT_USER()两个函数查看所使用的用户。
•USER()函数返回你在客户端登陆时指定的用户名和主机名。
•CURRENT_USER()函数返回的是MySQL使用授权表中的哪个用户来认证你的登录请求。

这里发现,我使用'server'@'localhost'这个账户登录数据库(因为在本地登陆时没指定主机,默认是以localhost登录),但是数据库使用的是''@'localhost'这个账户来进行登录认证,而''@'localhost'这个匿名用户是没有密码的,因此我输入空密码登录成功了。但是登录后,所对应的用户的匿名用户。

一般在MySQL在安装完毕后,我们使用mysql_install_db这个脚本生成授权表,会默认创建''@'localhost'这个匿名用户。正是因为这个匿名用户,影响了其他用户从本地登录的认证。

那么MySQL是如何进行用户身份认证呢?

一、当用户从客户端请求登陆时,MySQL将授权表中的条目与客户端所提供的条目进行比较,包括用户的用户名,密码和主机。授权表中的Host字段是可以使用通配符作为模式进行匹配的,如test.example.com, %.example.com, %.com和%都可以匹配test.example.com这个主机。授权表中的User字段不允许使用模式匹配,但是可以有一个空字符的用户名代表匿名用户,并且空字符串可以匹配所有的用户名,就像通配符一样。 当user表中的Host和User有多个值可以匹配客户端提供的主机和用户名时,MySQL将user表读入内存,并且按照一定规则排序,按照排序规则读取到的第一个匹配客户端用户名和主机名的条目对客户端进行身份验证。

二、排序规则:对于Host字段,按照匹配的精确程度进行排序,越精确的排序越前,例如当匹配test.example.com这个主机时, %.example.com比%.com更精确,而test.example.com比%.example.com更精确。对于User字段,非空的字符串用户名比空字符串匹配的用户名排序更靠前。 User和Host字段都有多个匹配值,MySQL使用主机名排序最前的条目,在主机名字段相同时再选取用户名排序更前的条目。因此,如果User和Host字段都有多个匹配值,主机名最精确匹配的条目被用户对用户进行认证。

了解了这个认证流程,就知道为什么server登录失败了。

使用GaMe在本机登录数据时,不指定-h参数默认为localhost主机登录,而在MySQL中有两个匹配的条目:'server'@'%'  和 ''@'localhost'

匿名用户能够匹配的原因上面说过,空字符串可以匹配所有的用户名,就像通配符一样。

根据MySQL认证时的排序规则,第一个条目的用户名排序更前,第二个条目的主机名更精确,排序更前。

而MySQL会优先使用主机名排序第一的条目进行身份认证,因此''@'localhost'被用户对客户端进行认证。因此,只有使用匿名用户的空密码才能登录进数据库。就会出现下面的情况了。

解决的方法:删除匿名用户(仅仅为了安全也有这个必要)

为什么root用户不会受影响,而只有普通用户不能从本地登录?

因为mysql_install_db脚本会在授权表中生成'root'@'localhost'这个账户。同样的,使用root登录MySQL 时,'root'@'localhost'和''@'localhost'都能匹配登录的账户,但是根据排序规则,主机名相同,而用户名非空字符串优先,因此'root'@'localhost'这个条目的排序更靠前。使用root本地登录是不会被匿名用户遮盖。