MySQL: compruebe si el usuario existe y suéltelo

84

No hay una forma estándar de verificar si existe un usuario de MySQL y, en función de eso, elimínelo. ¿Existen soluciones alternativas para esto?

Editar: necesito una forma directa de ejecutar esto sin arrojar un error,
por ejemplo

DROP USER test@localhost; :    
Cherian
fuente
1
¿Te refieres a un usuario de MySQL? ¿O un registro de usuario que está almacenando en una tabla en MySQL?
Jason Cohen
Parece que MariaDB tiene esta característica: mariadb.com/kb/en/mariadb/drop-user
Limited Atonement
1
para los futuros lectores: MySQL 5.7 tiene la característica 'DROP USER SI EXISTE', ver stackoverflow.com/questions/598190/...
Andrei Epure
1
@AndreiEpure, si pudieras poner esto como respuesta, lo marcaré como el correcto.
Cherian

Respuestas:

87

Esto funcionó para mí:

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

Esto crea el usuario si aún no existe (y le otorga un privilegio inofensivo), luego lo elimina de cualquier manera. Solución encontrada aquí: http://bugs.mysql.com/bug.php?id=19166

Actualizaciones: @Hao recomienda agregar IDENTIFIED BY; @andreb (en los comentarios) sugiere deshabilitar NO_AUTO_CREATE_USER.

trata bien a tus mods
fuente
5
De hecho, en la página del manual de concesión de MySQL dice: USO: Sinónimo de "sin privilegios"
stivlo
6
Esto ya no es una opción. :( La versión actual de MySQL ya no crea un nuevo usuario para la declaración GRANT. Fue una "característica" que agregaron.;) Parece que la opción de Cherian es la única que funciona actualmente.
GazB
1
@Zasurus. dev.mysql.com/doc/refman/5.1/en/grant.html (también 5.5 y 5.6) parece sugerir que estás equivocado. Hay una opción de "no creación automática de usuarios". A menos que no entienda bien el manual, indica que la concesión creará un usuario si no existe.
andreb
@andreb Quizás la opción "NO_AUTO_CREATE_USER" estaba activada cuando probé esto o de forma predeterminada (ya que no la he cambiado). Si tengo tiempo, intentaré esto para desactivar esta opción y volver a intentarlo. Hay algunos informes de errores abiertos con esta opción, tal vez uno de esos también sea el problema. :)
GazB
Vea también la respuesta de @ Hao. Necesitaba el IDENTIFIED BYpara que esto realmente funcionara.
Mateo
14

A la respuesta de phyzome (la más votada), me parece que si pones "identificado por" al final de la declaración de concesión, el usuario se creará automáticamente. Pero si no lo hace, el usuario no se crea. El siguiente código funciona para mí,

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

Espero que esto ayude.

Hao
fuente
Tenía algunos scripts antiguos sin eso IDENTIFICADO POR 'contraseña'; parte que funcionó en 5.6. Pero no lo hizo en 5.7. Agregar la parte IDENTIFICADA POR 'contraseña' funcionó para mí.
joensson
13

Encontré la respuesta a esto en uno de los foros de MySQL. Necesitaremos usar un procedimiento para eliminar al usuario.

El usuario aquí es "prueba" y "databaseName" el nombre de la base de datos.


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
fuente
Gracias @Cherian. No estoy seguro de si esta sigue siendo la mejor manera de hacer las cosas en 2017, ¡pero al menos es un camino a seguir! No puedo creer que esto siga siendo tan difícil ...
JMac
Solo para su información, siempre debe incluir la URL de su fuente (por ejemplo: encontró la respuesta desde uno de los formularios mysql . O desde uno de los formularios mysql (fuente aquí)
4
DROP USER IF EXISTS 'user'@'localhost' ;

eso funciona para mí sin arrojar ningún error en Maria DB, también debería funcionar para ti

Sathish Neel
fuente
2
En MySQL 5.7 y posteriores, seguro. ... Por suerte, la versión más nueva que usamos aquí es la 5.5.
Tetsujin
4

Actualización: a partir de MySQL 5.7, puede usar DROP USER IF EXISTSstatement. Ref: https://dev.mysql.com/doc/refman/5.7/en/drop-user.html

Sintaxis: DROP USER [IF EXISTS] user [, user] ...

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

FYI (y para la versión anterior de MySQL), esta es una mejor solución ... !!!

El siguiente SP le ayudará a eliminar el usuario 'tempuser'@'%'ejecutandoCALL DropUserIfExistsAdvanced('tempuser', '%');

Si desea eliminar a todos los usuarios nombrados 'tempuser'(digamos 'tempuser'@'%', 'tempuser'@'localhost'y 'tempuser'@'192.168.1.101') ejecute SP como ¡¡¡ CALL DropUserIfExistsAdvanced('tempuser', NULL);Esto eliminará todos los usuarios nombrados tempuser!!! seriamente...

Ahora, por favor, eche un vistazo al SP mencionado 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 ;

Uso:

CALL DropUserIfExistsAdvanced('tempuser', '%'); para eliminar usuario 'tempuser'@'%'

CALL DropUserIfExistsAdvanced('tempuser', '192.168.1.101'); para eliminar usuario 'tempuser'@'192.168.1.101'

CALL DropUserIfExistsAdvanced('tempuser', NULL);para eliminar todos los usuarios nombrados 'tempuser'(por ejemplo, decir 'tempuser'@'%', 'tempuser'@'localhost'y 'tempuser'@'192.168.1.101')

rajukoyilandy
fuente
3

Um ... ¿Por qué todas las complicaciones y trucos?

En lugar de usar DROP USER ... Simplemente puede eliminar al usuario de la tabla mysql.user (que no arroja un error si el usuario no existe), y luego eliminar los privilegios para aplicar el cambio.

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

- ACTUALIZAR -

Estaba equivocado. No es seguro eliminar al usuario de esa manera. Necesita usar DROP USER. Dado que es posible tener las opciones de mysql configuradas para no crear usuarios automáticamente a través de subvenciones (una opción que uso), todavía no recomendaría ese truco. Aquí hay un fragmento de un procedimiento almacenado que funciona para mí:

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
fuente
¿Comparte por qué "no es seguro" ...? ¿Seguro para quién de qué manera?
dagelf
Bueno, ya que publiqué esto hace más de un año, no pretendo recordar al 100% a qué me refería. Estoy bastante seguro de que quise decir que la confiabilidad no elimina al usuario del sistema por completo. Creo que DROP USER logra más que simplemente eliminar una fila de la tabla mysql.user. Lo siento, no puedo pensar en cuáles son esos detalles ahora.
BuvinJ
Si estuviera adivinando, diría que los registros de privilegios no se eliminan, sino que quedan "huérfanos". (¿Dependiendo de su configuración?)
BuvinJ
2

Con respecto a la respuesta de @ Cherian, se pueden eliminar las siguientes líneas:

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

Este fue un error anterior a 5.1.23. Después de esa versión, estos ya no son necesarios. Entonces, para la conveniencia de copiar / pegar, aquí es lo mismo con las líneas anteriores eliminadas. De nuevo, por ejemplo, "test" es el usuario y "databaseName" es la base de datos; y esto fue por este error .

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
fuente
2

Escribí este procedimiento inspirado en la respuesta de Cherian. La diferencia es que en mi versión el nombre de usuario es un argumento del procedimiento (y no está codificado). También estoy haciendo un FLUSH PRIVILEGES muy necesario después de eliminar al usuario.

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 ;

También publiqué este código en el sitio web CodeReview ( /codereview/15716/mysql-drop-user-if-exists )

MadSeb
fuente
2
DROP USER 'user'@'localhost';

El comando anterior eliminará al usuario de la base de datos, sin embargo, es importante saber si el mismo usuario ya está usando la base de datos, esa sesión no terminará hasta que el usuario cierre esa sesión. Es importante tener en cuenta que el usuario eliminado TODAVÍA accederá a la base de datos y realizará cualquier operación. DEJAR AL USUARIO NO BAJA LA SESIÓN DE USUARIO ACTUAL

Prabhakar Undurthi
fuente
0

Combinando la respuesta de phyzome (que no funcionó de inmediato para mí) con el comentario de andreb (que explica por qué no lo hizo) terminé con este código aparentemente funcional que deshabilita temporalmente el modo NO_AUTO_CREATE_USER si está activo:

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
fuente
0

en la terminal hacer:

sudo mysql -u root -p

Introduce la contraseña.

select user from mysql.user;

ahora elimine el usuario 'the_username'

DROP USER the_unername;

reemplace 'the_username' con el usuario que desea eliminar.

Messou
fuente
-1

En caso de tener un servidor escolar donde los alumnos trabajaron mucho. Puede limpiar el desorden de la siguiente manera:

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;
ene
fuente
-6

Si quiere decir que desea eliminar una gota de una tabla si existe, puede usar el DELETEcomando, por ejemplo:

 DELETE FROM users WHERE user_login = 'foobar'

Si ninguna fila coincide, no es un error.

Jason Cohen
fuente
2
Creo que el OP se refiere a un usuario de base de datos real.
Tomalak
6
Esta es la solución más simple de la OMI. Solo necesita SQL correcto: ELIMINAR DE mysql.user DONDE user = 'foobar'
John Rix