为什么 MySQL GRANT 没有创建相应的用户账户?

6

我安装了Percona Toolkit来使用pt-show-grants,但它没有显示所有的授权。当我运行它时,看到以下输出:

-- Grants dumped by pt-show-grants
-- Dumped from server Localhost via UNIX socket, MySQL 5.5.43-log at 2015-06-11 09:19:19
-- Grants for 'bob'@'12.34.56.78'
GRANT SUPER ON *.* TO 'bob'@'12.34.56.78' IDENTIFIED BY PASSWORD '*4F72B97CAAAAAAAAAAA9C38064C4CCB18CA0DD8';
GRANT SELECT ON `mydb`.* TO 'bob'@'12.34.56.78';
...

在这种情况下,bob只是一个用户。但所有的网站都使用特定的凭据,例如开发人员Bob可能会为他的example.com网站拥有一个帐户,称为bob_examplecom_1。当我显示该帐户的授权时:
mysql> SHOW GRANTS FOR 'bob_examplecom_1'@'localhost';
+-------------------------------------------------------------------------------------------------------------------------+
| Grants for bob_examplecom_1@localhost                                                                                   |
+-------------------------------------------------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'bob_examplecom_1'@'localhost' IDENTIFIED BY PASSWORD '*74AE8018AAAAAAAAAAAAAAAABB87B5C83E650CB' |
| GRANT ALL PRIVILEGES ON `bob_core`.* TO 'bob_examplecom_1'@'localhost' WITH GRANT OPTION                            |
| GRANT ALL PRIVILEGES ON `bob_examplecom_main`.* TO 'bob_examplecom_1'@'localhost' WITH GRANT OPTION                      |
| GRANT ALL PRIVILEGES ON `bob_blog`.* TO 'bob_examplecom_1'@'localhost'                                    |
+-------------------------------------------------------------------------------------------------------------------------+
4 rows in set (0.00 sec)

然而,当我尝试查找相关用户时:
mysql> SELECT User, Host FROM mysql.user WHERE User LIKE 'bob\_%';
Empty set (0.00 sec)

假设原始的GRANT没有创建关联的用户账户?还要注意,上面是一个网站的例子,有很多个网站。我可能错过了什么,但我期望在某种模式下看到NO_AUTO_CREATE_USER

mysql> SELECT @@GLOBAL.sql_mode;
+-------------------+
| @@GLOBAL.sql_mode |
+-------------------+
|                   |
+-------------------+
1 row in set (0.00 sec)

所以,我的问题是我想使用pt-show-grants为这个开发服务器上的新用户创建一个SQL文件,其中包含需要运行的许多GRANT,但我不知道该如何操作。我是否需要回顾性地创建与GRANT相匹配的用户帐户?我应该在将来更改一些设置和/或以不同的方式设置帐户吗?
更新:我刚刚运行了FLUSH PRIVILEGES,所有工作正常且没有与mysql.user中的帐户相关联的GRANT都消失了。这是否意味着它们永久消失了,所有内容都需要手动重新创建?为什么会发生这种情况?我查看了MySQL命令历史记录,没有发现过去删除这些帐户的命令。此服务器的正常运行时间超过400天,并且在此期间所有站点都能正常工作,几乎没有任何问题。
更新2:我不得不重新创建所有帐户。这次,使用GRANT USAGE然后授予权限确实创建了用户帐户。我的问题现在很简单:
为什么MySQL GRANT在执行GRANT时没有创建关联的用户帐户?

“关联账户”是什么意思?mysql.user.user 是可能用户的列表。 - Rick James
是的,正如问题所述,当我第一次运行“GRANT”时,它从未被创建,尽管在运行“SHOW GRANTS FOR ...”时显示了权限,但它们没有出现在“mysql.user”中。 - LeonardChallis
我认为你需要提供控制台转储以便查看发生了什么。我无法复制。另外,为什么要使用pt-show-grants而不是只使用mysql客户端的SHOW GRANTS命令? - winmutt
正如我在问题中所说的那样,现在账户已经正确创建了,我认为我无法再次重建它。此外,我想使用 pt-show-grants,因为它会将输出标准化,这样可以将其作为备份放入版本控制中。 - LeonardChallis
1个回答

5
根据您描述的行为,似乎使用DELETE语句从mysql.user表中删除了行,而不是使用DROP USER语句。通过DML语句(DELETE、INSERT、UPDATE)对权限表(mysql.user、mysql.db等)进行的更改不会立即生效。MySQL已经读取了这些表,并且信息保存在内存中。权限检查针对内存存储进行;MySQL不检查表的内容。因此,可以对mysql.user表进行更改,而不必反映出这些更改对有效权限的影响。FLUSH PRIVILEGES语句会导致MySQL重新读取所有权限表,并重建权限信息的“内存”存储。
回答您的问题:
Q: 原始GRANT是否没有创建关联的用户帐户?
Q: 为什么MySQL GRANT在执行GRANT时没有创建关联的用户帐户?
A: 如果成功完成,则“新”用户的GRANT确实创建了用户帐户。适当的行已添加到mysql.user表中,并且权限已生效(更改还应用于“内存”权限结构)。
Q: 这是否意味着它们永远消失了,需要手动重新创建所有内容?
A: 是的。如果mysql.user表中不存在行,则需要重新创建这些行。可以从备份中恢复mysql.user、mysql.db表中的行。
Q: 为什么会发生这种情况?
A: 正如之前提到的,可能有人无意中对mysql.user表运行了DELETE语句。 (还可能是TRUNCATE或DROP和CREATE。执行包括DROP TABLE语句的mysqldump脚本中的SQL,以从旧备份重新加载表?)如果没有对表执行此类操作,则另一个可能性是MyISAM表变得损坏,并且修复损坏导致行丢失。 (MyISAM表的已知问题之一;也是我们备份数据库并测试还原的原因之一。)
以下是行为演示...从mysql.user中删除行不会立即反映在有效权限中:
验证用户不存在:
mysql> SELECT USER, HOST FROM mysql.user WHERE USER LIKE 'bob' ;
Empty set (0.00 sec)
mysql> SHOW GRANTS FOR 'bob'@'192.168.11.121' ;
ERROR 1141 (42000): There is no such grant defined for user 'bob' on host '192.168.11.121'

使用GRANT语句创建用户:
mysql> GRANT SELECT ON ergo.* TO 'bob'@'192.168.11.121' IDENTIFIED BY 'mysecret';
Query OK, 0 rows affected (0.00 sec)

检查mysql.user表的内容和有效权限:

mysql> SELECT USER, HOST FROM mysql.user WHERE USER LIKE 'bob' ;
+------+----------------+
| USER | HOST           |
+------+----------------+
| bob  | 192.168.11.121 |
+------+----------------+
1 row in set (0.00 sec)

mysql> SHOW GRANTS FOR 'bob'@'192.168.11.121' ;
+-----------------------------------------------------------------------------------------------------------------+
| Grants for bob@192.168.11.121                                                                                   |
+-----------------------------------------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'bob'@'192.168.11.121' IDENTIFIED BY PASSWORD '*440A4F469FD488A1C73204842936CC18A62A7D7F' |
| GRANT SELECT ON `ergo`.* TO 'bob'@'192.168.11.121'                                                              |
+-----------------------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)

从mysql.user表中删除行(使用DML操作而不是DROP USER语句)

mysql> DELETE FROM mysql.user WHERE USER = 'bob' AND HOST = '192.168.11.121';
Query OK, 1 row affected (0.00 sec)

MySQL用户表中已删除行,但权限仍然有效:

mysql> SELECT USER, HOST FROM mysql.user WHERE USER LIKE 'bob' ;
Empty set (0.00 sec)

mysql> SHOW GRANTS FOR 'bob'@'192.168.11.121' ;
+-----------------------------------------------------------------------------------------------------------------+
| Grants for bob@192.168.11.121                                                                                   |
+-----------------------------------------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'bob'@'192.168.11.121' IDENTIFIED BY PASSWORD '*440A4F469FD488A1C73204842936CC18A62A7D7F' |
| GRANT SELECT ON `ergo`.* TO 'bob'@'192.168.11.121'                                                              |
+-----------------------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)

强制MySQL从mysql.user表中重新构建权限...

mysql> FLUSH PRIVILEGES ;
Query OK, 0 rows affected (0.00 sec)

权限已不再生效:

mysql> SHOW GRANTS FOR 'bob'@'192.168.11.121' ;
ERROR 1141 (42000): There is no such grant defined for user 'bob' on host '192.168.11.121'

谢谢您的回复。我同意你所说的,但我的问题是我看不到 DELETE FROM mysql.user 步骤是如何或在哪里发生的。我已经搜索了 .mysql_history 文件以查找具有正确权限运行它们的任何用户,并且什么都没有找到。有没有任何缩小范围的建议? - LeonardChallis
可能是先使用 TRUNCATE 再跟上一些有选择性的 INSERT 语句?也可能是 DROP、CREATE 和 INSERT,就像从 mysqldump 的 .sql 文件中(危险地)没有包含 --skip-add-drop-table 选项那样。.mysql_history 文件通常有一个最大大小限制,旧条目会被删除。这并不是所有运行的语句的完整历史记录。通过 TCP 连接的远程客户端执行的语句不会记录在 .mysql_history 中。此外,表损坏和修复可能导致行丢失。 - spencer7593
感谢@spencer7593,老实说我看不出这种情况会发生 - 在我们的小工作场所中只有我才能访问或了解上述内容(这让我看起来很糟糕:P),但您的答案是正确的,解释足以让我愉快地授予奖励。 - LeonardChallis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接