MySQL: проверьте, существует ли пользователь, и удалите его

84

Не существует стандартного способа проверить, существует ли пользователь MySQL, и на основе этого удалить его. Есть ли обходные пути для этого?

Изменить: мне нужен прямой способ запустить это, не вызывая ошибки,
например

DROP USER test@localhost; :    
Cherian
источник
1
Вы имеете в виду пользователя MySQL? Или запись пользователя, которую вы храните в таблице в MySQL?
Джейсон Коэн
Похоже, у MariaDB есть такая функция: mariadb.com/kb/en/mariadb/drop-user
lmat - Reinstate Monica
1
для будущих читателей: MySQL 5.7 имеет функцию DROP USER IF EXISTS, см. stackoverflow.com/questions/598190/…
Андрей
1
@AndreiEpure, если бы вы могли просто указать это как ответ, я отмечу его как правильный.
Cherian

Ответы:

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
6
Это уже не вариант. :( Текущая версия MySQL больше не создает нового пользователя для оператора GRANT. Это была «функция», которую они добавили.;) Похоже, что опция Cherian - единственная, которая работает в настоящее время.
ГазБ 06
1
@Zasurus. dev.mysql.com/doc/refman/5.1/en/grant.html (также 5.5 и 5.6), похоже, предполагает, что вы ошибаетесь. Есть опция «без автоматического создания пользователя». Если я не неправильно понимаю руководство, оно указывает, что грант создаст пользователя, если он не существует.
andreb
@andreb Возможно, опция «NO_AUTO_CREATE_USER» была включена, когда я пробовал это, или по умолчанию (например, я не менял ее). Если у меня будет время, я попробую отключить эту опцию и повторить попытку. Есть несколько открытых отчетов об ошибках с этой опцией, возможно, одна из них также является проблемой. :)
GazB
См. Также ответ @ Hao. Мне нужен IDENTIFIED BYбыл, чтобы это действительно работало.
Мэтью
14

На ответ phyzome (получивший наибольшее количество голосов) мне кажется, что если вы поставите «идентифицировано» в конце утверждения предоставления, пользователь будет создан автоматически. Но если вы этого не сделаете, пользователь не будет создан. Следующий код работает для меня,

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

Надеюсь это поможет.

Хао
источник
У меня было несколько старых сценариев без этого ИДЕНТИФИЦИРОВАННОГО «пароля»; часть, которая работала на 5.6. Но не на 5.7. Добавление части IDENTIFIED BY 'пароль' помогло мне.
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
источник
Спасибо @Cherian Я не уверен, что это все еще лучший способ делать что-то в 2017 году, но, по крайней мере, это путь вперед! Я не могу поверить, что это все еще так сложно ...
JMac
К вашему сведению, вы всегда должны включать URL-адрес своего источника (например: нашел ответ в одной из форм mysql . Или из одной из форм mysql (источник здесь)
4
DROP USER IF EXISTS 'user'@'localhost' ;

это работает для меня, не вызывая никаких ошибок в Maria DB, он должен работать и для вас

Сатиш Нил
источник
2
Конечно, в MySQL 5.7 и выше. ... К счастью, последняя версия, которую мы используем, - 5.5.
tetsujin
4

Обновление: с MySQL 5.7 вы можете использовать DROP USER IF EXISTSоператор. Ссылка: https://dev.mysql.com/doc/refman/5.7/en/drop-user.html

Синтаксис: DROP USER [IF EXISTS] user [, user] ...

Пример: DROP USER IF EXISTS 'jeffrey'@'localhost';

FYI (и для более старой версии MySQL), это лучшее решение ... !!!

Следующий SP поможет вам удалить пользователя 'tempuser'@'%', выполнивCALL DropUserIfExistsAdvanced('tempuser', '%');

Если вы хотите удалить всех пользователей с именами 'tempuser'(скажем 'tempuser'@'%', 'tempuser'@'localhost'и 'tempuser'@'192.168.1.101'), выполните SP как 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')

Rajukoyilandy
источник
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;
BuvinJ
источник
Поделитесь, почему это «небезопасно» ...? Безопасно для кого в каком смысле?
dagelf
Что ж, поскольку я опубликовал это более года назад, я не буду утверждать, что помню на 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» - это база данных; и это было из-за этого бага .

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
j4w7
источник
2

Я написал эту процедуру, вдохновившись ответом Чериана. Разница в том, что в моей версии имя пользователя является аргументом процедуры (а не жестко закодировано). Я также выполняю очень необходимые ПРИВИЛЕГИИ ПРОМЫВКИ после удаления пользователя.

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 )

MadSeb
источник
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 на пользователя, которого вы хотите удалить.

Messou
источник
-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: УДАЛИТЬ ИЗ mysql.user WHERE user = 'foobar'
Джон Рикс