MySQL: Перевірте, чи існує користувач, і скиньте його


84

Не існує стандартного способу перевірити, чи існує користувач MySQL, і виходячи з цього, його відкинути. Чи є для цього обхідні шляхи?

Редагувати: мені потрібен прямий спосіб запустити це, не видаючи помилки,
наприклад

DROP USER test@localhost; :    

1
Ви маєте на увазі користувача MySQL? Або запис користувача, який ви зберігаєте в таблиці в MySQL?
Джейсон Коен,

Схоже, MariaDB має таку функцію: mariadb.com/kb/en/mariadb/drop-user
Обмежена

1
для майбутніх читачів: MySQL 5.7 має функцію "ПАДАЙТЕ КОРИСТУВАЧА, ЩО ІСНУЄ", див. stackoverflow.com/questions/598190/…
Андрій Епуре

1
@AndreiEpure, якщо ви могли б просто поставити це як відповідь, я позначу його як правильний.
Черіан

Відповіді:



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. Вони додали "Особливість".;) Схоже, опція Черіана є єдиною, яка працює на даний момент.
GazB

1
@Zasurus. dev.mysql.com/doc/refman/5.1/en/grant.html (також 5.5 та 5.6), схоже, припускає, що ви помиляєтесь. Існує опція "немає автоматичного створення користувача". Якщо я не неправильно розумію інструкцію, це вказує на те, що grant створить користувача, якщо його не існує.
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. Додавання ІДЕНТИФІКОВАНОЇ «паролем» частини зробило для мене фокус.
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

Просто FYI, ви завжди повинні включати URL-адресу свого джерела (Наприклад: Знайшов відповідь з однієї з форм mysql . Або з однієї з форм mysql (джерело тут)

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

це працює для мене, не видаючи жодних помилок у Марії БД, це теж повинно працювати для вас


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), це краще рішення ... !!!

Наступний ІП допоможе вам видалити користувача 'tempuser'@'%', виконавшиCALL DropUserIfExistsAdvanced('tempuser', '%');

Якщо ви хочете видалити всіх користувачів з іменем 'tempuser'(скажімо 'tempuser'@'%', 'tempuser'@'localhost'та 'tempuser'@'192.168.1.101'), виконайте SP, як CALL DropUserIfExistsAdvanced('tempuser', NULL);Це видалить усіх іменованих користувачів tempuser!!! серйозно ...

Тепер, будь ласка, подивіться на згаданий ІП 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

Ну, оскільки я опублікував це більше року тому, я не буду стверджувати, що пам'ятаю на 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

2

Я написав цю процедуру, натхненний відповіддю Черіана. Різниця полягає в тому, що в моїй версії ім’я користувача є аргументом процедури (і не кодується жорстко). Я також роблю вкрай необхідні 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;

тепер видаліть користувача 'ім'я_користувача'

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 стосується реального користувача бази даних.
Томалак

6
Це найпростіше рішення IMO. Просто потрібен правильний SQL: ВИДАЛИТИ З mysql.user WHERE user = 'foobar'
Джон Рікс,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.