MySQL:检查用户是否存在并将其删除


84

没有标准的方法可以检查MySQL用户是否存在并基于该用户删除它。有什么解决方法吗?

编辑:我需要一种直接的方法来运行此而不抛出错误,
例如

DROP USER test@localhost; :    

1
您是说MySQL用户吗?还是您要存储在MySQL表中的用户记录?
贾森·科恩,

看起来MariaDB具有此功能:mariadb.com/kb/zh-CN/mariadb/drop-user
有限赎罪

1
对于未来的读者:MySQL的5.7具有以下特征:“DROP用户是否存在”,见stackoverflow.com/questions/598190/...
安德烈·伊普

1
@AndreiEpure如果您可以将此作为答案,我会将其标记为正确的答案。
Cherian

Answers:



87

这为我工作:

GRANT USAGE ON *.* TO 'username'@'localhost';
DROP USER 'username'@'localhost';

如果用户尚不存在,则会创建该用户(并授予其无害特权),然后以任何一种方式将其删除。在此处找到解决方案:http : //bugs.mysql.com/bug.php?id=19166

更新:@Hao建议添加IDENTIFIED BY; @andreb(在评论中)建议禁用NO_AUTO_CREATE_USER


5
实际上,在MySQL授予手册页中它说:用法:“无特权”的同义词
stivlo 2011年

6
这不再是一个选择。:(当前版本的MySQL不再为GRANT语句创建新用户。这是它们添加的“功能” ;;)看起来Cherian的选项是当前唯一可用的选项。
GazB 2011年

1
@Zasurus。dev.mysql.com/doc/refman/5.1/en/grant.html(以及5.5和5.6)似乎表明您错了。没有“不自动创建用户”选项。除非我对手册有误解,否则它表示授权将创建一个用户(如果不存在)。
andreb 2012年

@andreb尝试此操作时或默认情况下,“ NO_AUTO_CREATE_USER”选项处于启用状态(因为我没有更改它)。如果有时间,我将尝试关闭此选项,然后重试。有一些使用此选项的未解决错误报告,也许也是问题之一。:)
GazB 2012年

参见@郝的答案。我需要IDENTIFIED BY使它真正起作用。
马修

14

对于phyzome的回答(获得最高投票的人),在我看来,如果您在Grant声明的末尾加上“ identified by”,则会自动创建用户。但是,如果不这样做,则不会创建用户。以下代码对我有用,

GRANT USAGE ON *.* TO 'username'@'localhost' IDENTIFIED BY 'password';
DROP USER 'username'@'localhost';

希望这可以帮助。


我有一些旧脚本,但没有用“密码”标识;适用于5.6的部分。但是没有在5.7上。添加IDENTIFIED BY'password'部分对我有用。
joensson

13

从一个MySQL论坛中找到了答案。我们需要使用一个过程来删除用户。

这里的用户是“ test”和“ databaseName”的数据库名称。


SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='ANSI';
USE databaseName ;
DROP PROCEDURE IF EXISTS databaseName.drop_user_if_exists ;
DELIMITER $$
CREATE PROCEDURE databaseName.drop_user_if_exists()
BEGIN
  DECLARE foo BIGINT DEFAULT 0 ;
  SELECT COUNT(*)
  INTO foo
    FROM mysql.user
      WHERE User = 'test' and  Host = 'localhost';
   IF foo > 0 THEN
         DROP USER 'test'@'localhost' ;
  END IF;
END ;$$
DELIMITER ;
CALL databaseName.drop_user_if_exists() ;
DROP PROCEDURE IF EXISTS databaseName.drop_users_if_exists ;
SET SQL_MODE=@OLD_SQL_MODE ;

CREATE USER 'test'@'localhost' IDENTIFIED BY 'a'; GRANT ALL PRIVILEGES ON databaseName.* TO 'test'@'localhost' WITH GRANT OPTION


感谢@Cherian我不确定这是否仍然是2017年的最佳做法,但至少是前进的方向!我不敢相信这仍然很难...
JMac

仅供参考,您应该始终增加源的网址(例如:从一种mysql形式中找到答案或从一种mysql形式中找到答案(在此处提供来源)

4
DROP USER IF EXISTS 'user'@'localhost' ;

它对我有用,而不会在Maria DB中抛出任何错误,它也应该对您有用


2
当然,在MySQL 5.7及更高版本上。…幸运的是,我们在这里使用的最新版本是5.5。
铁通

4

更新: 从MySQL 5.7开始,您可以使用DROP USER IF EXISTSstatement。参考:https : //dev.mysql.com/doc/refman/5.7/en/drop-user.html

句法: DROP USER [IF EXISTS] user [, user] ...

例: DROP USER IF EXISTS 'jeffrey'@'localhost';

仅供参考(对于旧版本的MySQL),这是一个更好的解决方案... !!!

以下SP将'tempuser'@'%'通过执行以下操作来帮助您删除用户CALL DropUserIfExistsAdvanced('tempuser', '%');

如果要删除所有名为 'tempuser'(例如和)的'tempuser'@'%',请像这样执行SP,这将删除所有名为!!!的用户!认真地...'tempuser'@'localhost''tempuser'@'192.168.1.101'CALL DropUserIfExistsAdvanced('tempuser', NULL);tempuser

现在请看上面提到的SP DropUserIfExistsAdvanced

DELIMITER $$

DROP PROCEDURE IF EXISTS `DropUserIfExistsAdvanced`$$

CREATE DEFINER=`root`@`localhost` PROCEDURE `DropUserIfExistsAdvanced`(
    MyUserName VARCHAR(100)
    , MyHostName VARCHAR(100)
)
BEGIN
DECLARE pDone INT DEFAULT 0;
DECLARE mUser VARCHAR(100);
DECLARE mHost VARCHAR(100);
DECLARE recUserCursor CURSOR FOR
    SELECT `User`, `Host` FROM `mysql`.`user` WHERE `User` = MyUserName;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET pDone = 1;

IF (MyHostName IS NOT NULL) THEN
    -- 'username'@'hostname' exists
    IF (EXISTS(SELECT NULL FROM `mysql`.`user` WHERE `User` = MyUserName AND `Host` = MyHostName)) THEN
        SET @SQL = (SELECT mResult FROM (SELECT GROUP_CONCAT("DROP USER ", "'", MyUserName, "'@'", MyHostName, "'") AS mResult) AS Q LIMIT 1);
        PREPARE STMT FROM @SQL;
        EXECUTE STMT;
        DEALLOCATE PREPARE STMT;
    END IF;
ELSE
    -- check whether MyUserName exists (MyUserName@'%' , MyUserName@'localhost' etc)
    OPEN recUserCursor;
    REPEAT
        FETCH recUserCursor INTO mUser, mHost;
        IF NOT pDone THEN
            SET @SQL = (SELECT mResult FROM (SELECT GROUP_CONCAT("DROP USER ", "'", mUser, "'@'", mHost, "'") AS mResult) AS Q LIMIT 1);
            PREPARE STMT FROM @SQL;
            EXECUTE STMT;
            DEALLOCATE PREPARE STMT;
        END IF;
    UNTIL pDone END REPEAT;
END IF;
FLUSH PRIVILEGES;
END$$

DELIMITER ;

用法:

CALL DropUserIfExistsAdvanced('tempuser', '%'); 删除用户 'tempuser'@'%'

CALL DropUserIfExistsAdvanced('tempuser', '192.168.1.101'); 删除用户 'tempuser'@'192.168.1.101'

CALL DropUserIfExistsAdvanced('tempuser', NULL);删除指定的所有用户'tempuser'(例如,比方说'tempuser'@'%''tempuser'@'localhost''tempuser'@'192.168.1.101'


3

嗯...为什么所有的并发症和技巧?

而不是使用DROP USER ...您可以简单地从mysql.user表中删除该用户(如果该用户不存在,则不会引发错误),然后刷新特权以应用更改。

DELETE FROM mysql.user WHERE User = 'SomeUser' AND Host = 'localhost';
FLUSH PRIVILEGES;

-更新-

我错了。这样删除用户是不安全的。您确实需要使用DROP USER。由于可以将mysql选项设置为不通过授权自动创建用户(我使用的一个选项),因此我仍然不建议使用该技巧。这是一个对我有用的存储过程的摘要:

DECLARE userCount INT DEFAULT 0;
SELECT COUNT(*) INTO userCount FROM mysql.user WHERE User = userName AND Host='localhost';
IF userCount > 0 THEN
    SET @S=CONCAT("DROP USER ", userName, "@localhost" );
    PREPARE stmt FROM @S;
    EXECUTE stmt;
    SELECT CONCAT("DROPPED PRE-EXISTING USER: ", userName, "@localhost" ) as info;
END IF;
FLUSH PRIVILEGES;

是否分享为什么它“不安全” ...?用什么方式对谁安全?
dagelf '16

好吧,自从我一年多以前发布此信息以来,我不会声称要记住100%的内容。我敢肯定,我的意思是说这并不可靠,无法将用户完全从系统中移除。我认为DROP USER可以完成的工作不仅仅是从mysql.user表中删除一行。抱歉,我现在想不出这些细节了!
BuvinJ

如果我猜到了,我会说特权记录没有被删除,而是变成了“孤立的”?(取决于您的设置吗?)
BuvinJ

2

关于@Cherian的答案,可以删除以下几行:

SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='ANSI';
...
SET SQL_MODE=@OLD_SQL_MODE;
...

这是5.1.23之前的错误。在该版本之后,不再需要这些。因此,为方便复制/粘贴,此处的内容与上述删除的内容相同。同样,出于示例目的,“ test”是用户,“ databaseName”是数据库;这是这个bug引起的

DROP PROCEDURE IF EXISTS databaseName.drop_user_if_exists ;
DELIMITER $$
CREATE PROCEDURE databaseName.drop_user_if_exists()
BEGIN
  DECLARE foo BIGINT DEFAULT 0 ;
  SELECT COUNT(*)
  INTO foo
    FROM mysql.user
      WHERE User = 'test' and  Host = 'localhost';
   IF foo > 0 THEN
         DROP USER 'test'@'localhost' ;
  END IF;
END ;$$
DELIMITER ;
CALL databaseName.drop_user_if_exists() ;
DROP PROCEDURE IF EXISTS databaseName.drop_users_if_exists ;

CREATE USER 'test'@'localhost' IDENTIFIED BY 'a';
GRANT ALL PRIVILEGES  ON databaseName.* TO 'test'@'localhost'
 WITH GRANT OPTION

2

我写这篇程序的灵感来自Cherian的答案。区别在于,在我的版本中,用户名是过程的参数(而不是硬编码)。删除用户后,我还在做一个非常必要的FLUSH PRIVILEGES。

DROP PROCEDURE IF EXISTS DropUserIfExists;
DELIMITER $$
CREATE PROCEDURE DropUserIfExists(MyUserName VARCHAR(100))
BEGIN
  DECLARE foo BIGINT DEFAULT 0 ;
  SELECT COUNT(*)
  INTO foo
    FROM mysql.user
      WHERE User = MyUserName ;
   IF foo > 0 THEN
         SET @A = (SELECT Result FROM (SELECT GROUP_CONCAT("DROP USER"," ",MyUserName,"@'%'") AS Result) AS Q LIMIT 1);
         PREPARE STMT FROM @A;
         EXECUTE STMT;
         FLUSH PRIVILEGES;
   END IF;
END ;$$
DELIMITER ;

我也将此代码发布在了CodeReview网站上(/codereview/15716/mysql-drop-user-if-exists


2
DROP USER 'user'@'localhost';

上面的命令将从数据库中删除该用户,但是,重要的是要知道同一用户是否已经在使用该数据库,该会话将不会结束,直到该用户关闭该会话为止。重要的是要注意,被删除的用户将仍然访问数据库并执行任何操作。 删除用户不会删除当前的用户会话


0

结合phyzome的答案(对我来说不是立即可用)和andreb的注释(这说明了为什么没有这样做),我得到了这个看似有效的代码,如果激活了,它将暂时禁用NO_AUTO_CREATE_USER模式:

set @mode = @@SESSION.sql_mode;
set session sql_mode = replace(replace(@mode, 'NO_AUTO_CREATE_USER', ''), ',,', ',');
grant usage on *.* to 'myuser'@'%';
set session sql_mode = @mode;
drop user 'myuser'@'%';

0

在终端执行:

sudo mysql -u root -p

输入密码。

select user from mysql.user;

现在删除用户“ the_username”

DROP USER the_unername;

将“ the_username”替换为要删除的用户。


-1

如果您有一所学校的服务器,学生们的工作量很大。您可以通过以下方式清理混乱:

delete from user where User != 'root' and User != 'admin';
delete from db where User != 'root' and User != 'admin';

delete from tables_priv;
delete from columns_priv;

flush privileges;

-6

如果您要删除表中存在的子集,则可以使用以下DELETE命令,例如:

 DELETE FROM users WHERE user_login = 'foobar'

如果没有行匹配,那不是错误。


2
我认为OP是指真正的数据库用户。
Tomalak

6
这是IMO最简单的解决方案。只是需要正确的SQL:DELETE FROM mysql.user WHERE USER = 'foobar的'
约翰·里克斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.