MySQL:如何列出无权访问现有数据库的所有用户

时间:2017-02-24 12:42:47

标签: mysql sql

我正在3个不同的mySQL服务器(运行5.0.51a-24 + lenny5-log,5.5.54-0 + deb7u2和5.6.35)上进行一些“春季清理”,有数百个数据库和数百个用户。

所以我正在寻找一个返回用户列表的查询,这些用户无权访问服务器上的任何现有数据库。

如果我查看mysql.user,我可以看到服务器上的所有用户。到现在为止还挺好。现在,如果我查看mysql.db,我可以看到他们与数据库的关系。所以我认为得到结果可能很简单:

SELECT * 
   FROM mysql.`user` tblusers
WHERE NOT EXISTS (SELECT * 
                     FROM mysql.`db` tbldbrelation
                     WHERE tblusers.User = tbldbrelation.User)

然而,由于关系没有更新,当数据库被删除时(据我所知),单独看这两件事,只会给我系统,服务和root用户等。我需要另一种方法。显然show databases;将返回服务器上当前的所有数据库。但是如何考虑到这一点 - 以便我获得一个用户列表,这些用户无法访问任何现有的特定数据库?

3 个答案:

答案 0 :(得分:1)

我会使用Percona Toolkit's pt-show-grants转储我的所有用户及其权限。然后查找除USAGE之外没有任何权限的用户。

例如,我刚刚在我的本地MySQL实例上创建了一个名为dummy的虚拟用户,但没有授予用户任何数据库的任何权限。

pt-show-grants的输出:

$ pt-show-grants h=127.0.0.1
-- Grants dumped by pt-show-grants
-- Dumped from server 127.0.0.1 via TCP/IP, MySQL 8.0.0-dmr at 2017-02-25 18:35:54
-- Grants for 'dummy'@'127.0.0.1'
GRANT USAGE ON *.* TO `dummy`@`127.0.0.1`;
-- Grants for 'mysql.sys'@'localhost'
GRANT SELECT ON `sys`.`sys_config` TO `mysql.sys`@`localhost`;
GRANT TRIGGER ON `sys`.* TO `mysql.sys`@`localhost`;
GRANT USAGE ON *.* TO `mysql.sys`@`localhost`;
-- Grants for 'root'@'localhost'
GRANT ALL PRIVILEGES ON *.* TO `root`@`localhost` WITH GRANT OPTION;
GRANT PROXY ON ''@'' TO 'root'@'localhost' WITH GRANT OPTION;

mysql.sys用户和root用户是MySQL 8.0的标准配置。上面的行显示dummy具有USAGE特权,但没有别的。

答案 1 :(得分:1)

你的问题是一个挑战回答,但最后,即使我们得到一个简单的"查询以显示哪些用户帐户没有分配任何类型的权限(是的,根本没有权限),并用它来清理我们的数据库:)

现在要了解查询,让它分成一定级别

第一级,列出每个没有列级访问权限的用户。

SELECT C.User FROM mysql.user C LEFT JOIN mysql.columns_priv ON ( mysql.columns_priv.User = C.User ) WHERE (Column_priv=0 OR Column_priv IS NULL) AND mysql.columns_priv.Db IS NULL

第二级,列出没有表级权限的用户,以及只有没有列级访问权限的用户。

SELECT B.User FROM mysql.user B LEFT JOIN mysql.tables_priv ON ( mysql.tables_priv.User = B.User ) WHERE
mysql.tables_priv.Db IS NULL AND (Table_priv=0 OR Table_priv IS NULL) AND (Column_priv=0 OR Column_priv IS NULL)
AND B.User IN (
    SELECT C.User FROM mysql.user C LEFT JOIN mysql.columns_priv ON ( mysql.columns_priv.User = C.User ) WHERE
    (Column_priv=0 OR Column_priv IS NULL) AND mysql.columns_priv.Db IS NULL)

第三级,列出没有数据库级权限的用户,并仅列出那些无法访问前两个查询的用户。

SELECT A.User FROM mysql.user A LEFT JOIN mysql.db ON ( mysql.db.User = A.User ) WHERE
mysql.db.Db IS NULL
AND A.User IN (
    SELECT B.User FROM mysql.user B LEFT JOIN mysql.tables_priv ON ( mysql.tables_priv.User = B.User ) WHERE
    mysql.tables_priv.Db IS NULL AND (Table_priv=0 OR Table_priv IS NULL) AND (Column_priv=0 OR Column_priv IS NULL)
    AND B.User IN (
        SELECT C.User FROM mysql.user C LEFT JOIN mysql.columns_priv ON ( mysql.columns_priv.User = C.User ) WHERE
        (Column_priv=0 OR Column_priv IS NULL) AND mysql.columns_priv.Db IS NULL)
)

第三级,检查在数据库级别具有访问权限的任何人,并仅列出不具有表/列级别访问权限的人。

最后。

SELECT mysql.user.Host, mysql.user.User
FROM mysql.user WHERE mysql.user.User IN (
    SELECT A.User FROM mysql.user A LEFT JOIN mysql.db ON ( mysql.db.User = A.User ) WHERE
    mysql.db.Db IS NULL
    AND A.User IN (
        SELECT B.User FROM mysql.user B LEFT JOIN mysql.tables_priv ON ( mysql.tables_priv.User = B.User ) WHERE
        mysql.tables_priv.Db IS NULL AND (Table_priv=0 OR Table_priv IS NULL) AND (Column_priv=0 OR Column_priv IS NULL)
        AND B.User IN (
            SELECT C.User FROM mysql.user C LEFT JOIN mysql.columns_priv ON ( mysql.columns_priv.User = C.User ) WHERE
            (Column_priv=0 OR Column_priv IS NULL) AND mysql.columns_priv.Db IS NULL)
        )
) AND CONCAT(Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Reload_priv,Shutdown_priv,Process_priv,File_priv,Grant_priv,References_priv,Index_priv,Alter_priv,Show_db_priv,Super_priv,Create_tmp_table_priv,Lock_tables_priv,Execute_priv,Repl_slave_priv,Repl_client_priv,Create_view_priv,Show_view_priv,Create_routine_priv,Alter_routine_priv,Create_user_priv,Event_priv,Trigger_priv,Create_tablespace_priv) NOT LIKE '%Y%'

仅列出未分配全局访问权限的用户,并匹配其他子查询的条件。

"非常直接"

编辑:请提供反馈,因为此查询仅在5.5版本上进行了测试。

答案 2 :(得分:0)

我设法弄清楚如何做到这一点,使用一个不依赖于第三方工具的相对简单的查询 - 并且在MySQL版本中得到支持 - 至少5.0.51a到5.6.35,这是我我正在跑步。

SELECT DISTINCT USER
FROM mysql.user a
    WHERE EXISTS(
        SELECT *
        FROM mysql.db b
            WHERE b.User = a.User
            AND NOT EXISTS(SELECT schema_name 
                FROM information_schema.schemata c
                    WHERE SUBSTRING_INDEX(b.Db,'\_',1) = SUBSTRING_INDEX(c.SCHEMA_NAME,'_',1)
                    OR SUBSTRING_INDEX(b.Db,'_',1) = SUBSTRING_INDEX(c.SCHEMA_NAME,'_',1)                                           
            )
    )

这将向mysql.user查询mysql.db中也存在的用户,但schema_name表中没有设置架构。结果将是用户列表。

这可能需要根据您的具体设置进行一些定制。几点说明:

  • 我已将其设为DISTINCT(SELECT DISTINCT USER),因为我的许多用户都有多次登录 来自不同地点(即user@123.123.123.123,user @ localhost, 等等)。我只想要一个输入。你可能想要一些东西 其他。编辑:对大多数情况更有用的是SELECT CONCAT(USER, "@", HOST)而不是
  • 我们构建表和用户名的方式,我有很多用户 以及名称中包含下划线(_)的表。 (用户通常创建为" domainname_tld"数据库为" domainname_tld_subdomain")。并且由于 通过脚本创建其中一些的方式, 下划线有时会使用反斜杠(\)进行转义 实际上是数据库名称,但不在架构中。这就是我在最后的WHERE语句中使用SUBSTRING_INDEX方法的原因。
相关问题