MySQL: Sprawdź, czy użytkownik istnieje i usuń go

84

Nie ma standardowego sposobu sprawdzenia, czy użytkownik MySQL istnieje i na tej podstawie go upuść. Czy są jakieś obejścia tego problemu?

Edycja: potrzebuję prostego sposobu, aby to uruchomić bez generowania błędu,
np

DROP USER test@localhost; :    
Cherian
źródło
1
Masz na myśli użytkownika MySQL? Albo rekord użytkownika, który przechowujesz w tabeli w MySQL?
Jason Cohen
Wygląda na to, że MariaDB ma tę funkcję: mariadb.com/kb/en/mariadb/drop-user
Limited Atonement
1
dla przyszłych czytelników: MySQL 5.7 ma funkcję „UPUŚĆ UŻYTKOWNIKA, JEŚLI ISTNIEJE”, patrz stackoverflow.com/questions/598190/ ...
Andrei Epure
1
@Andrei: Jasne, że jeśli możesz podać to jako odpowiedź, oznaczę ją jako właściwą.
Cherian

Odpowiedzi:

87

To zadziałało dla mnie:

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

Tworzy to użytkownika, jeśli jeszcze nie istnieje (i zapewnia mu nieszkodliwe przywileje), a następnie usuwa go w obu przypadkach. Znalezione rozwiązanie tutaj: http://bugs.mysql.com/bug.php?id=19166

Aktualizacje: @Hao zaleca dodanie IDENTIFIED BY; @andreb (w komentarzach) sugeruje wyłączenie NO_AUTO_CREATE_USER.

dobrze traktuj swoje mody
źródło
6
To już nie jest opcja. :( Obecna wersja MySQL nie tworzy już nowego użytkownika dla instrukcji GRANT. To była "funkcja", którą dodali.;) Wygląda na to, że opcja Cheriana jest jedyną, która obecnie działa.
GazB
1
@Zasurus. dev.mysql.com/doc/refman/5.1/en/grant.html (także 5.5 i 5.6) wydaje się sugerować, że się mylisz. Dostępna jest opcja „brak automatycznego tworzenia użytkowników”. O ile nie zrozumiem źle instrukcji, oznacza to, że grant utworzy użytkownika, jeśli nie istnieje.
andreb
@andreb Być może opcja „NO_AUTO_CREATE_USER” była włączona, gdy próbowałem tego lub domyślnie (ponieważ nie zmieniłem tego). Jeśli będę miał czas, spróbuję wyłączyć tę opcję i spróbuję ponownie. Jest kilka otwartych zgłoszeń błędów z tą opcją, być może jednym z nich jest również problem. :)
GazB
Zobacz również odpowiedź @ Hao. Potrzebowałem, IDENTIFIED BYaby to faktycznie działało.
Matthew
14

Odpowiadając phyzome (najwyżej głosowanemu), wydaje mi się, że jeśli na końcu oświadczenia o przyznaniu dotacji wstawisz słowo „zidentyfikowany przez”, użytkownik zostanie utworzony automatycznie. Ale jeśli tego nie zrobisz, użytkownik nie zostanie utworzony. Poniższy kod działa dla mnie,

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

Mam nadzieję że to pomoże.

Hao
źródło
Miałem kilka starych skryptów bez tego IDENTIIFIED BY „hasło”; część, która pracowała nad 5.6. Ale nie na 5.7. Dodanie części IDENTIFIED BY „hasło” załatwiło sprawę.
joensson
13

Znalazłem odpowiedź na to jedno z forów MySQL. Będziemy musieli użyć procedury, aby usunąć użytkownika.

Tutaj użytkownik to „test”, a „databaseName” to nazwa bazy danych.


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
źródło
Dzięki @Cherian Nie jestem pewien, czy jest to nadal najlepszy sposób robienia rzeczy w 2017 roku, ale przynajmniej jest to droga naprzód! Nie mogę uwierzyć, że to wciąż jest takie trudne ...
JMac,
Po prostu do Twojej wiadomości powinieneś zawsze dołączać adres URL swojego źródła (Np .: Znaleziono odpowiedź z jednego z formularzy mysql . Lub z jednego z formularzy mysql (źródło tutaj)
4
DROP USER IF EXISTS 'user'@'localhost' ;

to działa dla mnie bez rzucania żadnych błędów w Maria DB, powinno działać również dla ciebie

Sathish Neel
źródło
2
Oczywiście w MySQL 5.7 i nowszych wersjach. ... Szczęściarz, najnowsza wersja, której tu używamy to 5.5.
tetsujin
4

Aktualizacja: Od MySQL 5.7 możesz użyć DROP USER IF EXISTSinstrukcji. Odniesienie: https://dev.mysql.com/doc/refman/5.7/en/drop-user.html

Składnia: DROP USER [IF EXISTS] user [, user] ...

Przykład: DROP USER IF EXISTS 'jeffrey'@'localhost';

FYI (i dla starszej wersji MySQL), jest to lepsze rozwiązanie ... !!!

Poniższy SP pomoże ci usunąć użytkownika 'tempuser'@'%', wykonującCALL DropUserIfExistsAdvanced('tempuser', '%');

Jeśli chcesz usunąć wszystkich użytkowników nazwanych 'tempuser'(słownie 'tempuser'@'%', 'tempuser'@'localhost'i 'tempuser'@'192.168.1.101') wykonywanie SP jak CALL DropUserIfExistsAdvanced('tempuser', NULL);ta spowoduje usunięcie wszystkich użytkowników nazwanych tempuser!!! poważnie...

Teraz spójrz na wspomniane 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 ;

Stosowanie:

CALL DropUserIfExistsAdvanced('tempuser', '%'); aby usunąć użytkownika 'tempuser'@'%'

CALL DropUserIfExistsAdvanced('tempuser', '192.168.1.101'); aby usunąć użytkownika 'tempuser'@'192.168.1.101'

CALL DropUserIfExistsAdvanced('tempuser', NULL);usunięcie wszystkich użytkowników nazwanych 'tempuser'(np., powiedzmy 'tempuser'@'%', 'tempuser'@'localhost'i 'tempuser'@'192.168.1.101')

rajukoyilandy
źródło
3

Um ... Po co te wszystkie komplikacje i sztuczki?

Zamiast tego użyj DROP USER ... Możesz po prostu usunąć użytkownika z tabeli mysql.user (co nie powoduje błędu, jeśli użytkownik nie istnieje), a następnie opróżnić uprawnienia, aby zastosować zmianę.

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

-- AKTUALIZACJA --

Myliłem się. Usunięcie takiego użytkownika nie jest bezpieczne. Musisz użyć DROP USER. Ponieważ możliwe jest ustawienie opcji mysql tak, aby nie tworzyły użytkowników automatycznie poprzez grants (opcja, której używam), nadal nie polecałbym tej sztuczki. Oto fragment z procedury składowanej, która działa dla mnie:

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
źródło
Czy udostępniaj, dlaczego to „nie jest bezpieczne”…? Bezpieczne dla kogo w jaki sposób?
dagelf
Cóż, odkąd opublikowałem to ponad rok temu, nie twierdzę, że pamiętam w 100%, o czym mówiłem. Jestem prawie pewien, że chodziło mi o to, że nie powoduje to całkowitego usunięcia użytkownika z systemu. Myślę, że DROP USER daje więcej niż tylko usunięcie wiersza z tabeli mysql.user. Przepraszam, nie mogę sobie przypomnieć, jakie są te szczegóły!
BuvinJ,
Gdybym zgadywał, powiedziałbym, że rekordy uprawnień nie są usuwane, ale zostają „osierocone”? (W zależności od twoich ustawień?)
BuvinJ
2

Jeśli chodzi o odpowiedź @ Cherian, można usunąć następujące wiersze:

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

To był błąd sprzed 5.1.23. Po tej wersji nie są już potrzebne. Tak więc, dla wygody kopiowania / wklejania, tutaj jest to samo z usuniętymi powyższymi wierszami. Na przykład w celach „test” jest użytkownikiem, a „databaseName” jest bazą danych; a to było z tego błędu .

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
źródło
2

Napisałem tę procedurę inspirowaną odpowiedzią Cheriana. Różnica polega na tym, że w mojej wersji nazwa użytkownika jest argumentem procedury (a nie zakodowana na stałe). Robię też bardzo potrzebne PRZYWILEJE FLUSH po usunięciu użytkownika.

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 ;

Opublikowałem również ten kod na stronie CodeReview ( /codereview/15716/mysql-drop-user-if-exists )

MadSeb
źródło
2
DROP USER 'user'@'localhost';

Powyższe polecenie spadnie użytkownika z bazy danych, jednak jest ważne , aby wiedzieć, czy ten sam użytkownik korzysta już z bazy danych, że sesja nie zakończy się, dopóki użytkownik nie zamknie tej sesji. Należy pamiętać, że upuszczony użytkownik NADAL będzie uzyskiwał dostęp do bazy danych i wykonywał wszelkie operacje. UPUSZCZENIE UŻYTKOWNIKA NIE PRZESUWA AKTUALNEJ SESJI UŻYTKOWNIKA

Prabhakar Undurthi
źródło
0

Łącząc odpowiedź phyzome (która nie zadziałała od razu dla mnie) z komentarzem andreba (który wyjaśnia, dlaczego tak się nie stało) otrzymałem ten pozornie działający kod, który tymczasowo wyłącza tryb NO_AUTO_CREATE_USER, jeśli jest aktywny:

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'@'%';
Svullo
źródło
0

w terminalu zrobić:

sudo mysql -u root -p

Podaj hasło.

select user from mysql.user;

teraz usuń użytkownika „the_username”

DROP USER the_unername;

zamień „the_username” na użytkownika, którego chcesz usunąć.

Messou
źródło
-1

Jeśli masz szkolny serwer, na którym uczniowie dużo pracowali. Możesz po prostu posprzątać bałagan:

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;
Jan
źródło
-6

Jeśli masz na myśli, że chcesz usunąć drop z tabeli, jeśli istnieje, możesz użyć DELETEpolecenia, na przykład:

 DELETE FROM users WHERE user_login = 'foobar'

Jeśli żaden wiersz nie pasuje, nie jest to błąd.

Jason Cohen
źródło
2
Myślę, że OP odnosi się do prawdziwego użytkownika bazy danych.
Tomalak
6
To najprostsze rozwiązanie IMO. Potrzebuje tylko poprawnego kodu SQL: DELETE FROM mysql.user WHERE user = 'foobar'
John Rix