MySQL User Privileges list in one shot - mysql

SET #s:='';
SELECT #s:= CONCAT('SHOW GRANTS FOR \'',user,'\'#\'',host,'\';') FROM mysql.user where user = 'root';
PREPARE stmt FROM #s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
I dont mind to achieve this using any stored proc. Let say I have 2 users with root
'root'#'%' and 'root'#'localhost'
What I want is to get result of multiple prepare statements. But the above only executes the last one (ie 'root'#'localhost'). The two challenges I faced
PREPARE / EXECUTE stmt can execute only one query at a time
Only Stored proc can use loop
Objective: All I want is to execute two 'SHOW GRANTS FOR' in one shot

This in also not the answer, as the question is more on the execution of multiple prepared statements, Another example can be like in case we need to OPTIMIZE all tables in a database, #wchiquito answer is accepted for that reason
Finally Percona already came up with pt-show-grants
One more way I tried myself to get it along with the database-name. But this may not work on Version 5.7, In a more readable format would be
(SELECT `GRANTEE`, `TABLE_SCHEMA`, (CASE
WHEN GROUP_CONCAT(`PRIVILEGE_TYPE`) = 'SELECT' THEN 'READ ONLY'
WHEN (LOCATE('DELETE',GROUP_CONCAT(`PRIVILEGE_TYPE`))
+ LOCATE('UPDATE',GROUP_CONCAT(`PRIVILEGE_TYPE`))
+ LOCATE('INSERT',GROUP_CONCAT(`PRIVILEGE_TYPE`))
+ LOCATE('SELECT',GROUP_CONCAT(`PRIVILEGE_TYPE`))) >= 4 THEN 'READ+WRITE'
ELSE GROUP_CONCAT(`PRIVILEGE_TYPE` ORDER BY `PRIVILEGE_TYPE`)
END) AS 'PRIVILEGE_TYPE'
FROM INFORMATION_SCHEMA.SCHEMA_PRIVILEGES
WHERE GRANTEE NOT REGEXP '^......$'
GROUP BY `GRANTEE`, `TABLE_SCHEMA`)
UNION
(SELECT `GRANTEE`, 'All Databases' AS `TABLE_SCHEMA`, (CASE
WHEN GROUP_CONCAT(`PRIVILEGE_TYPE`) = 'SELECT' THEN 'READ ONLY'
WHEN (LOCATE('DELETE',GROUP_CONCAT(`PRIVILEGE_TYPE`))
+ LOCATE('UPDATE',GROUP_CONCAT(`PRIVILEGE_TYPE`))
+ LOCATE('INSERT',GROUP_CONCAT(`PRIVILEGE_TYPE`))
+ LOCATE('SELECT',GROUP_CONCAT(`PRIVILEGE_TYPE`))) >= 4 THEN 'READ+WRITE'
ELSE GROUP_CONCAT(`PRIVILEGE_TYPE` ORDER BY `PRIVILEGE_TYPE`)
END) AS 'PRIVILEGE_TYPE'
FROM INFORMATION_SCHEMA.USER_PRIVILEGES
WHERE GRANTEE NOT REGEXP '^......$'
GROUP BY `GRANTEE`
HAVING GROUP_CONCAT(`PRIVILEGE_TYPE`) != 'USAGE')

DROP PROCEDURE IF EXISTS `db`.`SP_UserRolePriv`;
DELIMITER $$
CREATE PROCEDURE `db`.`SP_UserRolePriv`()
BEGIN
DECLARE done int(10) default 0;
DECLARE Var_user varchar(25);
DECLARE Var_host varchar(25);
DECLARE QST text;
DECLARE cur_urp CURSOR FOR SELECT user,host FROM mysql.user;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur_urp;
tab_loop: LOOP
FETCH cur_urp INTO Var_user,Var_host;
IF done THEN
LEAVE tab_loop;
END IF;
-- SELECT CONCAT(Var_user,'#',Var_host) "User";
SET #QST = CONCAT('SHOW GRANTS FOR ',CONCAT('''',Var_user,'''#''',Var_host,''';'));
-- SELECT QST;
PREPARE stmt FROM #QST;
EXECUTE stmt ;
DEALLOCATE PREPARE stmt;
END LOOP;
CLOSE cur_urp;
END $$
DELIMITER ;
CALL `mysqlagent`.`SP_UserRolePriv`();

With the appropriate privileges, you can do something like:
mysql> system rm -f /tmp/get_show_grants.sql;
mysql> SELECT CONCAT('system rm -f /tmp/show_grants.sql;
SELECT CONCAT(\'SHOW GRANTS FOR \'\'\', `user`, \'\'\'#\'\'\', `host`,\'\'\';\')
INTO OUTFILE \'/tmp/show_grants.sql\'
FROM `mysql`.`user`
WHERE `user` = \'root\';
source /tmp/show_grants.sql;
system rm -f /tmp/show_grants.sql /tmp/get_show_grants.sql;
') INTO OUTFILE '/tmp/get_show_grants.sql';
Query OK, 1 row affected (0.00 sec)
mysql> source /tmp/get_show_grants.sql;
Query OK, 1 row affected (0.00 sec)
+---------------------------------------------------------------------+
| Grants for root#localhost |
+---------------------------------------------------------------------+
| GRANT ALL PRIVILEGES ON *.* TO 'root'#'localhost' WITH GRANT OPTION |
| GRANT PROXY ON ''#'' TO 'root'#'localhost' WITH GRANT OPTION |
+---------------------------------------------------------------------+
2 rows in set (0.00 sec)

Related

MySQL sugar syntax to create an authenticated, all-privileged user and its database

This is how I create an authenticated, all-privileged user and its database in MySQL through the MySQL CLI in Linux (Ubuntu with Bash):
cat <<-DBSTACK | mysql -u root -p"${dbrootp}"
CREATE (OR RE-CREATE IF NEEDED) USER "${domain}"#"localhost" IDENTIFIED BY "${dbuserp}";
CREATE (OR RE-CREATE IF NEEDED) DATABASE ${domain};
GRANT ALL PRIVILEGES ON ${domain}.* TO "${domain}"#"localhost";
DBSTACK
Is there some sugar syntax, or some high functionality that does all of that in a single line?
(would be better than running 5 lines - 2 for an here-document opener and delimiter, and 3 for MySQL).
I'm not aware of any in-built command that would perform all of these tasks as one, but you can easily define your own stored program to do it:
CREATE PROCEDURE addNewDomain(domain VARCHAR(32), password VARCHAR(32))
BEGIN
DECLARE db VARCHAR(66) DEFAULT CONCAT('`', REPLACE(domain, '`', '``'), '`');
DECLARE ac VARCHAR(76) DEFAULT CONCAT(db, '#localhost');
SET
#a := CONCAT('CREATE USER ', ac, ' IDENTIFIED BY ', QUOTE(password)),
#b := CONCAT('CREATE DATABASE ', db),
#c := CONCAT('GRANT ALL PRIVILEGES ON ', db, '.* TO ', ac)
;
PREPARE stmt FROM #a; EXECUTE stmt; DEALLOCATE PREPARE stmt;
PREPARE stmt FROM #b; EXECUTE stmt; DEALLOCATE PREPARE stmt;
PREPARE stmt FROM #c; EXECUTE stmt; DEALLOCATE PREPARE stmt;
END
Which you would then invoke with a single CALL statement:
CALL addNewDomain('foobar', 's3cr3t')
One advantage of this approach is that the procedure can be defined by a user with full CREATE and GRANT permissions, but permission to EXECUTE it granted to a user who does not have those permissions—then your shell script can connect to MySQL using the lower-privileged account (that can cause less damage, eg only set up new domains, if compromised).
Note that, in order to issue the CREATE PROCEDURE command (which contains ; characters) you will need to ensure your MySQL client's statement delimiter is set to something other than ; or else it will split the command into multiple separate statements when sending to the server. The MySQL CLI does this using the DELIMITER statement:
DELIMITER ;;
CREATE PROCEDURE addNewDomain(domain VARCHAR(32), password VARCHAR(32))
BEGIN
-- etc
END;;
DELIMITER ;
There's no combined syntax per the MySQL docs, presumably because - generally -
CREATE USER and CREATE DATABASE are executed once, while GRANT is executed more than once.
One way to reduce the syntax overhead is to encapsulate the SQL construction in a shell function. For bash, that might look like:
grant_sql() {
local user pass
user="${1:?Missing argument #1: MySQL user name}"
pass="${2:?Missing argument #2: password for MySQL user}"
cat <<EOSQL
CREATE USER "${user}"#"localhost" IDENTIFIED BY "${pass}";
CREATE DATABASE ${user};
GRANT ALL PRIVILEGES ON ${user}.* TO "${user}"#"localhost";
EOSQL
}
Then to fire it off like:
grant_sql "myUser" "itsPassword" | mysql -uroot -p...

How to write stored procedure to check Grant in MySql?

I want to create a stored procedure to check grant. I have tried by following way but I don't what I am missing here.
//simple Query "SHOW GRANTS FOR testuser #'192.168.1.180'" - It is working
CREATE DEFINER=`abc`#`localhost` PROCEDURE `SP_GetGrantAllPriviledge`(
IN Username TEXT,
IN Hostname TEXT
)
BEGIN
SHOW GRANTS FOR Username #Hostname; //doesn't work
END
Can anybody suggest what I am missing?
You can use the TABLE_PRIVILEGES in the INFORMATION_SCHEMA.
SELECT *
FROM INFORMATION_SCHEMA.TABLE_PRIVILEGES
WHERE `GRANTEE` = CONCAT('''', Username, '''#''', Hostname, '''')
#Hostname; is the source of issue
Update your SP with prepare statement:
CREATE PROCEDURE `SP_GetGrantAllPriviledge`(
IN Username TEXT,
IN Hostname TEXT
)
BEGIN
SET #sql = CONCAT('SHOW GRANTS FOR ',Username,' #',Hostname,'; ');
PREPARE stmt FROM #sql;
EXECUTE stmt;
END

mysql dynamic queries execution

I'm trying to write MySQL script dropping some tables selected by pattern but my procedure doesn't compile. Could anybody please advice what is wrong with it please?
delimiter #
drop procedure if exists drop_audit_tables #
create procedure drop_audit_tables()
begin
declare done int default false;
declare cmd varchar(4000);
declare cmds cursor for select 'drop table [' + table_name + ']' from information_schema.tables where table_name like '%_audit';
declare continue handler for not found set done = true;
open cmds;
tLoop: loop
fetch cmds into cmd;
if done then
leave tLoop;
end if;
PREPARE STMT FROM cmd;
EXECUTE STMT;
DEALLOCATE PREPARE STMT;
end loop tLoop;
close cmds;
end #
the error message:
[42000][1064] You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'cmd; EXECUTE STMT; DEALLOCATE PREPARE STMT; end loop tLoop; close cm' at line 13
You can avoid the cursor:
mysql> DROP TABLE IF EXISTS `one_audit`;
Query OK, 0 rows affected (0.00 sec)
mysql> DROP TABLE IF EXISTS `two_audit`;
Query OK, 0 rows affected (0.01 sec)
mysql> DROP TABLE IF EXISTS `three_audit`;
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE `one_audit`(`a` INT);
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE `two_audit`(`a` INT);
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE TABLE `three_audit`(`a` INT);
Query OK, 0 rows affected (0.00 sec)
mysql> SET #`drop_tables` := (
-> SELECT
-> CONCAT('DROP TABLE IF EXISTS ',
-> GROUP_CONCAT(CONCAT('`', `TABLE_NAME`, '`') SEPARATOR ', '))
-> FROM
-> `information_schema`.`TABLES`
-> WHERE
-> `TABLE_SCHEMA` = DATABASE() AND
-> `TABLE_TYPE` = 'BASE TABLE' AND
-> `TABLE_NAME` LIKE '%_audit'
-> );
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT #`drop_tables`;
+--------------------------------------------------------------+
| #`drop_tables` |
+--------------------------------------------------------------+
| DROP TABLE IF EXISTS `one_audit`, `three_audit`, `two_audit` |
+--------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> PREPARE `exec` FROM #`drop_tables`;
Query OK, 0 rows affected (0.00 sec)
Statement prepared
mysql> EXECUTE `exec`;
Query OK, 0 rows affected (0.00 sec)
mysql> DEALLOCATE PREPARE `exec`;
Query OK, 0 rows affected (0.00 sec)
You must be careful with the system variable group_concat_max_len.
UPDATE
Using cursor:
DELIMITER #
DROP PROCEDURE IF EXISTS `drop_audit_tables`#
CREATE PROCEDURE `drop_audit_tables`()
BEGIN
DECLARE `done` BOOL DEFAULT 0;
DECLARE `cmd` VARCHAR(4000);
DECLARE `cmds` CURSOR FOR
SELECT
CONCAT('DROP TABLE IF EXISTS `', `TABLE_NAME`, '`')
FROM
`information_schema`.`TABLES`
WHERE
`TABLE_SCHEMA` = DATABASE() AND
`TABLE_TYPE` = 'BASE TABLE' AND
`TABLE_NAME` LIKE '%_audit';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET `done` := 1;
OPEN `cmds`;
`tLoop`: LOOP
FETCH `cmds` INTO `cmd`;
IF `done` THEN
CLOSE `cmds`;
LEAVE `tLoop`;
END IF;
SET #`cmd` := `cmd`;
PREPARE `STMT` FROM #`cmd`;
EXECUTE `STMT`;
DEALLOCATE PREPARE `STMT`;
END LOOP `tLoop`;
SET #`cmd` := NULL;
END#
CALL `drop_audit_tables`#
DELIMITER ;
14.5.1 PREPARE
Syntax
PREPARE stmt_name FROM preparable_stmt
...
preparable_stmt is either a string literal or a user variable that
contains the text of the SQL statement.
...
Your line:
declare cmds cursor for select 'drop table [' + table_name + ']' from information_schema.tables where table_name like '%_audit';
.. uses table_name without defining it first.
Try defining it first with something like:
create procedure drop_audit_tables(IN table_name VARCHAR(64))
You may want to consider the security implications of taking a variable directly from the stored procedure and placing it into your ad-hoc query.
Still, define table_name somewhere. In this case table_name would be supplied as an argument to your stored procedure. Your task then is to gather an array of table names and run this code in a for/foreach loop.
Basic (non-robust) PHP (PDO)
/* Get the audit tables. */
$stmt = $pdo->query(`CALL get_audit_tables()`)
$tables = $stmt->fetch();
$stmt->close()
$stmt = $pdo->prepare('CALL drop_audit_tables(:table)')
/* Drop each audit table. */
foreach($tables as $table)
{
$stmt->bindParam(:table, $table, PDO::PARAM_STR)
$stmt->execute();
}
$stmt->close();
Something like that, anyway.
MySQL: CREATE PROCEDURE
Specifying a parameter as IN, OUT, or INOUT is valid only for a PROCEDURE. For a FUNCTION, parameters are always regarded as IN parameters.
PHP Manual: PDO::prepare
Prepares an SQL statement to be executed by the PDOStatement::execute() method. The SQL statement can contain zero or more named (:name) or question mark (?) parameter markers for which real values will be substituted when the statement is executed.
A solution like this would make your life easier. You only need to define a basic query that finds your audit tables. Less code. Simpler.

set name of table with variables in mysql [duplicate]

How do you build and use dynamic sql in a MySQL stored procedure?
After 5.0.13, in stored procedures, you can use dynamic SQL:
delimiter //
CREATE PROCEDURE dynamic(IN tbl CHAR(64), IN col CHAR(64))
BEGIN
SET #s = CONCAT('SELECT ',col,' FROM ',tbl );
PREPARE stmt FROM #s;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
//
delimiter ;
Dynamic SQL does not work in functions or triggers. See the MySQL documentation for more uses.
I don't believe MySQL supports dynamic sql. You can do "prepared" statements which is similar, but different.
Here is an example:
mysql> PREPARE stmt FROM
-> 'select count(*)
-> from information_schema.schemata
-> where schema_name = ? or schema_name = ?'
;
Query OK, 0 rows affected (0.00 sec)
Statement prepared
mysql> EXECUTE stmt
-> USING #schema1,#schema2
+----------+
| count(*) |
+----------+
| 2 |
+----------+
1 row in set (0.00 sec)
mysql> DEALLOCATE PREPARE stmt;
The prepared statements are often used to see an execution plan for a given query. Since they are executed with the execute command and the sql can be assigned to a variable you can approximate the some of the same behavior as dynamic sql.
Here is a good link about this:
Don't forget to deallocate the stmt using the last line!
Good Luck!
You can pass thru outside the dynamic statement using User-Defined Variables
Server version: 5.6.25-log MySQL Community Server (GPL)
mysql> PREPARE stmt FROM 'select "AAAA" into #a';
Query OK, 0 rows affected (0.01 sec)
Statement prepared
mysql> EXECUTE stmt;
Query OK, 1 row affected (0.01 sec)
DEALLOCATE prepare stmt;
Query OK, 0 rows affected (0.01 sec)
mysql> select #a;
+------+
| #a |
+------+
|AAAA |
+------+
1 row in set (0.01 sec)

MySQL: Check if the user exists and drop it

There’s not standard way to check if a MySQL user exists and based on that drop it. Are there any workarounds for this?
Edit: I need a straight way to run this without throwing up an error
e.g.
DROP USER test#localhost; :
This worked for me:
GRANT USAGE ON *.* TO 'username'#'localhost';
DROP USER 'username'#'localhost';
This creates the user if it doesn't already exist (and grants it a harmless privilege), then deletes it either way. Found solution here: http://bugs.mysql.com/bug.php?id=19166
Updates: #Hao recommends adding IDENTIFIED BY; #andreb (in comments) suggests disabling NO_AUTO_CREATE_USER.
Since MySQL 5.7 you can do a DROP USER IF EXISTS test
More info: http://dev.mysql.com/doc/refman/5.7/en/drop-user.html
To phyzome's answer (most highly voted one), it seems to me that if you put "identified by" at the end of the grant statement, the user will be created automatically. But if you don't, the user is not created. The following code works for me,
GRANT USAGE ON *.* TO 'username'#'localhost' IDENTIFIED BY 'password';
DROP USER 'username'#'localhost';
Hope this helps.
Found the answer to this from one of the MySQL forums. We’ll need to use a procedure to delete the user.
User here is “test” and “databaseName” the database name.
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
Update
As of MySQL 5.7 you can directly use DROP USER IF EXISTS statement.
https://dev.mysql.com/doc/refman/5.7/en/drop-user.html
DROP USER IF EXISTS 'user'#'localhost';
FYI (and for older version of MySQL), this is a better solution...!!!
The following SP will help you to remove user 'tempuser'#'%' by executing CALL DropUserIfExistsAdvanced('tempuser', '%');
If you want to remove all users named 'tempuser' (say 'tempuser'#'%', 'tempuser'#'localhost' and 'tempuser'#'192.168.1.101') execute SP like CALL DropUserIfExistsAdvanced('tempuser', NULL); This will delete all users named tempuser!!! seriously...
Now please have a look on mentioned 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 ;
Usage:
CALL DropUserIfExistsAdvanced('tempuser', '%'); to remove user 'tempuser'#'%'
CALL DropUserIfExistsAdvanced('tempuser', '192.168.1.101'); to remove user 'tempuser'#'192.168.1.101'
CALL DropUserIfExistsAdvanced('tempuser', NULL); to remove all users named 'tempuser' (eg., say 'tempuser'#'%', 'tempuser'#'localhost' and 'tempuser'#'192.168.1.101')
Um... Why all the complications and tricks?
Rather then using DROP USER... You can simply delete the user from the mysql.user table (which doesn't throw an error if the user does not exist), and then flush privileges to apply the change.
DELETE FROM mysql.user WHERE User = 'SomeUser' AND Host = 'localhost';
FLUSH PRIVILEGES;
-- UPDATE --
I was wrong. It's not safe to delete the user like that. You do need to use DROP USER. Since it is possible to have mysql options set to not create users automatically via grants (an option I use), I still wouldn't recommend that trick. Here's a snipet from a stored procedure that works for me:
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;
DROP USER IF EXISTS 'user'#'localhost' ;
that works for me without throwing any errors in Maria DB, it should work for u too
Regarding #Cherian's answer, the following lines can be removed:
SET #OLD_SQL_MODE=##SQL_MODE, SQL_MODE='ANSI';
...
SET SQL_MODE=#OLD_SQL_MODE;
...
This was a bug pre 5.1.23. After that version these are no longer required. So, for copy/paste convenience, here is the same with the above lines removed. Again, for example purposes "test" is the user and "databaseName" is the database; and this was from this bug.
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
I wrote this procedure inspired by Cherian's answer.
The difference is that in my version the user name is an argument of the procedure ( and not hard coded ) . I'm also doing a much necessary FLUSH PRIVILEGES after dropping the user.
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 ;
I also posted this code on the CodeReview website ( https://codereview.stackexchange.com/questions/15716/mysql-drop-user-if-exists )
DROP USER 'user'#'localhost';
The above command will drop the user from the database, however, it is Important to know if the same user is already using the database, that session will not end until the user closes that session. It is important to note that dropped user will STILL access the database and perform any operations.
DROPPING THE USER DOES NOT DROP THE CURRENT USER SESSION
Combining phyzome's answer (which didn't work right away for me) with andreb's comment (which explains why it didn't) I ended up with this seemingly working code that temporarily disables NO_AUTO_CREATE_USER mode if it is active:
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'#'%';
in terminal do:
sudo mysql -u root -p
enter the password.
select user from mysql.user;
now delete the user 'the_username'
DROP USER the_unername;
replace 'the_username' with the user that you want to delete.
In case you have a school server where the pupils worked a lot. You can just clean up the mess by:
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;
If you mean you want to delete a drop from a table if it exists, you can use the DELETE command, for example:
DELETE FROM users WHERE user_login = 'foobar'
If no rows match, it's not an error.