今天搭建一个测试环境时,遇到了一个很隐蔽的问题。有必要分享一下

|user|password|host|
+------+-------------------------------------------+--------------------+
|root|*81F5E21E35407D884A6CD4A731AEBFB6AF209E1B|localhost|1
|root||db-2.photo.xxx.org|2
|root||127.0.0.1|3
|root||::1|4
|      ||localhost|5
|      ||db-2.photo.xxx.org|6
|sys|*xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|db-2.photo.xxx.org|7
...
...
如上图所示,这个里面存在着两个用户名为空的情况。然后问题就是由此而起。
在本机(服务器,db-2.photo.xxx.orgmysql -usys -ppass -h`hostname`或者mysql -usys -ppass           - h`hostname-i`都提示无法连接。此时配置文件里面没有skip-name-resolve这个参数(DNS解析用的)而用户表里面明明有这个而且密码也对了啊?起初没有注意到这个空用户,没想到它的陷阱,搞了很久也没连上,后来只好请老大了,老大过来一看,直接dropuser''@db-2.photo.xxx.org(删掉这个空用户,老大V5),然后再连,OK搞定。
这是什么原因呢?
因为mysql在验证权限的时候,首先是验证host列,如果host列正确再验证user列,最后再验证password列,而现在按照我之前的连接语句:按照host列首先找到第6行,然后发现这行的user列为空(空匹配所有用户名),所以匹配到了这条记录,然后发现这条记录的密码为空,而我的连接语句里面有密码,那么就会报错。
好了,你可能会说要是我在连接的时候-h指定的是ip地址,而不是域名(db-2.photo.xxx.org)那么不就不会匹配到了这条记录么?但是我在前面说了skip-name-resolve这个参数我没有指定,那么就会DNS解析,所以还是会被域名匹配到的。于是我的连接语句改为mysql-usys-h`hostname-i`或者mysql-usys-h`hostname`此时就可以连接成功,但是请注意,虽然可以连接成功,但是实际上这个连上去的用户没有多大权限,此时的权限就是空用户所具有的权限,你就可以看出。(之前的理解有误,实际上与数据在物理磁盘上的顺序无关,因为将数据读到内存时会按照<hostname,username>进行排序)
所以解决办法就是:
1.
刚装好mysql后就直接删除那个空用户
2.
连接的时候,-h+ip连接,且在配置文件里面指定skip-name-resolve,这样同时还能消除DNS解析带来的性能影响
另外,如果直接指定了socket的话,也不会存在这个问题,此时连接就是通过socket,而不是tcp/ip同时,如果你在别的机器上连接肯定也没问题,因为空用户默认的host就是主机地址。
不明白mysql5.5为什么这样设计,在mysql5.1里面就没有这个空用户。(在这次转移博客的时候发现了mysql5.5bin目录下提供了一个mysql_secure_installation的脚本,里面就可以删除空用户等等,看来mysql还是知道这个安全问题是存在的)