1.9 许可问题
MySQL有复杂的权限方案,这使得你可以精确地设置哪些用户和主机可以或不可以执行这个或那个操作。从5.5版本开始,MySQL也有了可插拔式的身份验证模式。
尽管它有很多优势,但是这个方案很复杂。例如,让user1@hostA、user2@hostA和user1@hostB不同会很容易混淆它们的权限。当用户名相同而主机名变化的时候更是如此。
MySQL允许在对象和连接层面设置访问规则。可以限制某个用户对于特定的表、列等的访问权限。
用户通常会遇到两类权限问题:
应该有权限连接到服务器的用户无法连接,或者没有权限的用户可以连接;
用户可以连接到服务器,但是无法使用他们本应该可以访问的对象,或者可以访问他们无权访问的对象。
在解决这些问题之前,应该确认你是否可以连接到服务器。
当你作为解决问题的用户成功连接到服务器之后(后面的章节将讨论无法连接的情况),执行以下查询:
USER()函数会返回当用户连接到服务器时使用的连接参数。这些参数通常为指定的用户名和运行客户端的主机名。CURRENT_USER()函数会返回从权限表中选择的与访问权限相关的用户名和主机名对。mysqld用这些用户名和主机名对来检查数据库对象访问权限。通过比较这些函数的结果,可以找到mysqld使用的权限和预期不同的原因。一个典型的问题是对主机名使用通配符%:
如果此时我以sveta身份连接并尝试创建一个表,我就会获得下面的错误:
该问题在于,MySQL服务器认为sveta是sveta@localhost,而不是通配符:
如果你不理解为什么选择一台或另一台主机,可以进行如下查询:
MySQL在表中按照从访问最多的主机到访问最少的主机的顺序对行进行排序,然后使用第一个找到的值。因此,它把我当作sveta@localhost用户进行连接,此时该用户没有CREATE权限。
USER()、CURRENT_USER()函数和“SELECT user, host FROM mysql.user ORDER BY host DESE”查询语句是遇到权限问题时的首选。
另一种权限问题是你无法作为指定用户进行连接。在这种情况下,通常可以从错误消息中了解问题产生的原因,错误消息一般如下所示:
在看到这条消息以后,你了解了用户凭证。作为root超级用户进行连接,然后检查该用户是否存在以及是否拥有所需权限:
在这个输出信息中,你可以看到用户'sveta'@'localhost'仅仅对book数据库有权限,而对books数据库没有权限。现在,可以修复这个错误:赋予sveta@localhost用户必要的权限。
前面的示例讨论用户缺失必要权限的情况。对于用户被授予过多权限的情况也可以同样处理;仅需要移除不必要的权限。
警告 警告
MySQL的权限与其管控对象是分离的:这意味着当你赋予某用户权限时mysqld 不会检查其是否存在,同时当授权对象被删除时也不会移除相应权限。这样做的好处是允许我们预先授予必要的权限,但同时也有可能在不经意的使用中带来潜在的问题。
作为最佳实践,我推荐你仔细学习MySQL的权限工作机制。尤其是在你想要在用户对象级别授予权限的时候,因为你需要理解在一个级别授权是如何影响其他授权的。同样,对于撤消权限情形也一样重要,甚至更重要,因为如果你以为已经撤消了某个权限但它依然存在,这就会造成意外的访问。
[1] 版本5.6.3开始,也可以在UPDATE和DELETE上使用EXPLAIN方法,不过把语句转换成SELECT查询仍然有效,因为你可以方便地检查和操作实际的结果集,而不是仅使用EXPLAIN命令。这尤其适用于复杂的JOIN操作,尤其是当EXPLAIN输出的检查的行比实际更新的行还要多的时候。
[3] 第5章将详细介绍如何解决复制失败的问题,因此这里不再详细解释。
[4] MySQL企业级备份(MEB)以前也称作InnoDB热备份,是InnoDB表进行在线热备份和其他存储引擎的表进行在线备份的一个工具。第7章将讨论备份的方法。