MySQL: Kiểm tra xem người dùng có tồn tại không và loại bỏ nó


84

Không có cách tiêu chuẩn nào để kiểm tra xem người dùng MySQL có tồn tại hay không và dựa vào đó mà thả. Có bất kỳ giải pháp thay thế cho điều này?

Chỉnh sửa: Tôi cần một cách dễ dàng để chạy nó mà không gặp lỗi,
ví dụ:

DROP USER test@localhost; :    

1
Ý bạn là người dùng MySQL? Hoặc một bản ghi người dùng mà bạn đang lưu trữ trong một bảng trong MySQL?
Jason Cohen

Có vẻ như MariaDB có tính năng này: mariadb.com/kb/en/mariadb/drop-user
Limited Atonement,

1
cho độc giả trong tương lai: MySQL 5,7 có tính năng 'USER thả IF EXISTS', xem stackoverflow.com/questions/598190/...
Andrei Epure

1
@AndreiEpure nếu bạn có thể đặt đây là câu trả lời, tôi sẽ đánh dấu nó là câu trả lời đúng.
Cherian

Câu trả lời:



87

Điều này đã làm việc cho tôi:

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

Điều này tạo ra người dùng nếu nó chưa tồn tại (và cấp cho nó một đặc quyền vô hại), sau đó xóa nó theo cách nào đó. Giải pháp tìm thấy ở đây: http://bugs.mysql.com/bug.php?id=19166

Cập nhật: @Hao khuyên bạn nên thêm IDENTIFIED BY; @andreb (trong nhận xét) đề xuất tắt NO_AUTO_CREATE_USER.


5
Trong MySQL cấp trang hướng dẫn trên thực tế nó nói: SỬ DỤNG: Từ đồng nghĩa với “không có đặc quyền”
stivlo

6
Đây không còn là một lựa chọn. :( Phiên bản MySQL hiện tại không còn tạo người dùng mới cho câu lệnh GRANT nữa. Đó là "Tính năng" mà họ đã thêm.;) Có vẻ như tùy chọn của Cherian là tùy chọn duy nhất hoạt động hiện tại.
GazB

1
@Zasurus. dev.mysql.com/doc/refman/5.1/en/grant.html (cũng là 5.5 và 5.6) dường như cho thấy rằng bạn đã sai. Có tùy chọn "không có người dùng tự động tạo". Trừ khi tôi hiểu sai hướng dẫn sử dụng, nó chỉ ra rằng tài trợ sẽ tạo ra một người dùng nếu nó không tồn tại.
andreb

@andreb Có lẽ tùy chọn "NO_AUTO_CREATE_USER" đã được bật khi tôi thử điều này hoặc theo mặc định (như trong tôi chưa thay đổi nó). Nếu có thời gian, tôi sẽ thử tắt tùy chọn này và thử lại. Có một vài báo cáo lỗi mở với tùy chọn này có lẽ một trong những là vấn đề cũng :).
GazB

Hãy xem câu trả lời của @ Hao. Tôi cần IDENTIFIED BYđiều này để thực sự hoạt động.
Matthew

14

Đối với câu trả lời của phyzome (câu trả lời được bình chọn cao nhất), có vẻ như với tôi rằng nếu bạn đặt "xác định bởi" vào cuối tuyên bố tài trợ, người dùng sẽ được tạo tự động. Nhưng nếu bạn không làm như vậy, người dùng không được tạo. Đoạn mã sau phù hợp với tôi,

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

Hi vọng điêu nay co ich.


Tôi có một số tập lệnh cũ mà không được XÁC NHẬN BẰNG 'mật khẩu'; phần hoạt động trên 5.6. Nhưng không có vào ngày 5.7. Việc thêm phần 'mật khẩu' được XÁC NHẬN đã thực hiện thủ thuật đối với tôi.
joensson

13

Tìm thấy câu trả lời cho điều này từ một trong những diễn đàn MySQL. Chúng tôi sẽ cần sử dụng một quy trình để xóa người dùng.

Người dùng ở đây là “test” và “databaseName” là tên cơ sở dữ liệu.


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


Cảm ơn @Cherian Tôi không chắc liệu đây có còn là cách tốt nhất để làm việc trong năm 2017 hay không nhưng ít nhất nó cũng là một chặng đường phía trước! Tôi không thể tin rằng đây vẫn là khó khăn như vậy ...
JMac

Chỉ cần FYI bạn nên luôn luôn inclue url của nguồn của bạn (Ví dụ: Tìm thấy câu trả lời từ một trong những mysql hình thức hoặc từ một trong những hình thức mysql (nguồn ở đây).

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

hoạt động cho tôi mà không gây ra bất kỳ lỗi nào trong Maria DB, nó cũng sẽ hoạt động cho bạn


2
Chắc chắn là trên MySQL 5.7 trở lên. ... Thật may mắn cho tôi, phiên bản mới nhất mà chúng tôi sử dụng ở đây là 5.5.
tetsujin

4

Cập nhật: Kể từ MySQL 5.7, bạn có thể sử dụng DROP USER IF EXISTScâu lệnh. Tham khảo: https://dev.mysql.com/doc/refman/5.7/en/drop-user.html

Cú pháp: DROP USER [IF EXISTS] user [, user] ...

Thí dụ: DROP USER IF EXISTS 'jeffrey'@'localhost';

FYI (và cho phiên bản MySQL cũ hơn), đây là một giải pháp tốt hơn ... !!!

SP sau đây sẽ giúp bạn xóa người dùng 'tempuser'@'%'bằng cách thực thiCALL DropUserIfExistsAdvanced('tempuser', '%');

Nếu bạn muốn xóa tất cả người dùng có tên 'tempuser'(nói 'tempuser'@'%', 'tempuser'@'localhost''tempuser'@'192.168.1.101') thực thi SP như thế CALL DropUserIfExistsAdvanced('tempuser', NULL);này sẽ xóa tất cả người dùng có tên tempuser!!! nghiêm túc...

Bây giờ hãy xem SP đã đề cập 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 ;

Sử dụng:

CALL DropUserIfExistsAdvanced('tempuser', '%'); xóa người dùng 'tempuser'@'%'

CALL DropUserIfExistsAdvanced('tempuser', '192.168.1.101'); xóa người dùng 'tempuser'@'192.168.1.101'

CALL DropUserIfExistsAdvanced('tempuser', NULL);để xóa tất cả người dùng có tên 'tempuser'(ví dụ:., say 'tempuser'@'%', 'tempuser'@'localhost''tempuser'@'192.168.1.101')


3

Ừm ... Tại sao tất cả những phức tạp và thủ thuật?

Thay vào đó, sử dụng DROP USER ... Bạn có thể chỉ cần xóa người dùng khỏi bảng mysql.user (bảng này không gây ra lỗi nếu người dùng không tồn tại), rồi xóa các đặc quyền để áp dụng thay đổi.

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

- CẬP NHẬT -

Tôi đã sai. Không an toàn khi xóa người dùng như vậy. Bạn cần sử dụng DROP USER. Vì có thể có các tùy chọn mysql được đặt để không tự động tạo người dùng thông qua các khoản tài trợ (một tùy chọn tôi sử dụng), tôi vẫn sẽ không đề xuất thủ thuật đó. Đây là một đoạn trích từ một quy trình được lưu trữ phù hợp với tôi:

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;

Hãy chia sẻ tại sao nó "không an toàn" ...? An toàn cho ai theo cách nào?
dagelf

Chà, vì tôi đã đăng bài này hơn một năm trước nên tôi sẽ không tuyên bố nhớ 100% những gì tôi đang đề cập đến. Tôi khá chắc chắn rằng tôi muốn nói rằng nó không đáng tin cậy sẽ xóa người dùng khỏi hệ thống hoàn toàn. Tôi nghĩ rằng DROP USER thực hiện được nhiều việc hơn là chỉ xóa một hàng khỏi bảng mysql.user. Xin lỗi, tôi không thể nghĩ những chi tiết đó là gì!
BuvinJ

Nếu tôi đoán, tôi muốn nói rằng các bản ghi đặc quyền không bị xóa, mà trở thành "mồ côi"? (Tùy thuộc vào cài đặt của bạn?)
BuvinJ

2

Về câu trả lời của @ Cherian, có thể xóa các dòng sau:

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

Đây là một lỗi trước 5.1.23. Sau phiên bản đó, chúng không còn được yêu cầu nữa. Vì vậy, để thuận tiện sao chép / dán, ở đây là tương tự với các dòng trên được loại bỏ. Một lần nữa, đối với các mục đích ví dụ "kiểm tra" là người dùng và "databaseName" là cơ sở dữ liệu; và đây là từ lỗi này .

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

Tôi đã viết quy trình này lấy cảm hứng từ câu trả lời của Cherian. Sự khác biệt là trong phiên bản của tôi, tên người dùng là một đối số của thủ tục (và không được mã hóa cứng). Tôi cũng đang thực hiện các QUYỀN RIÊNG TƯ VỀ FLUSH rất cần thiết sau khi bỏ người dùng.

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 ;

Tôi cũng đã đăng mã này trên trang web CodeReview ( /codereview/15716/mysql-drop-user-if-exists )


2
DROP USER 'user'@'localhost';

Lệnh trên sẽ loại bỏ người dùng khỏi cơ sở dữ liệu, tuy nhiên, điều quan trọng là phải biết nếu cùng một người dùng đã sử dụng cơ sở dữ liệu, phiên đó sẽ không kết thúc cho đến khi người dùng đóng phiên đó. Điều quan trọng cần lưu ý là người dùng bị rớt sẽ VẪN truy cập cơ sở dữ liệu và thực hiện bất kỳ hoạt động nào. DROPPING NGƯỜI DÙNG KHÔNG XÓA PHẦN NGƯỜI DÙNG HIỆN TẠI


0

Kết hợp câu trả lời của phyzome (không hoạt động ngay với tôi) với nhận xét của andreb (giải thích lý do tại sao nó không), tôi đã kết thúc với đoạn mã dường như đang hoạt động này tạm thời tắt chế độ NO_AUTO_CREATE_USER nếu nó đang hoạt động:

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

trong thiết bị đầu cuối làm:

sudo mysql -u root -p

nhập mật khẩu.

select user from mysql.user;

bây giờ hãy xóa người dùng 'the_username'

DROP USER the_unername;

thay thế 'the_username' bằng người dùng mà bạn muốn xóa.


-1

Trong trường hợp bạn có một máy chủ trường học, nơi học sinh làm việc rất nhiều. Bạn chỉ có thể dọn dẹp đống lộn xộn bằng cách:

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

Nếu bạn muốn xóa một giọt khỏi bảng nếu nó tồn tại, bạn có thể sử dụng DELETElệnh, ví dụ:

 DELETE FROM users WHERE user_login = 'foobar'

Nếu không có hàng nào khớp thì đó không phải là lỗi.


2
Tôi nghĩ OP đề cập đến một người dùng cơ sở dữ liệu thực.
Tomalak

6
Đây là giải pháp đơn giản nhất IMO. Chỉ cần SQL đúng: DELETE FROM mysql.user ĐÂU user = 'foobar'
John Rix
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.