Search the MySQL manual:

4.3.1 GRANT and REVOKE Syntax

GRANT priv_type [(column_list)] [, priv_type [(column_list)] ...]
    ON {tbl_name | * | *.* | db_name.*}
    TO user_name [IDENTIFIED BY [PASSWORD] 'password']
        [, user_name [IDENTIFIED BY [PASSWORD] 'password'] ...]
    [REQUIRE
        NONE |
        [{SSL| X509}]
        [CIPHER cipher [AND]]
        [ISSUER issuer [AND]]
        [SUBJECT subject]]
    [WITH [GRANT OPTION | MAX_QUERIES_PER_HOUR # |
                          MAX_UPDATES_PER_HOUR # |
                          MAX_CONNECTIONS_PER_HOUR #]]

REVOKE priv_type [(column_list)] [, priv_type [(column_list)] ...]
    ON {tbl_name | * | *.* | db_name.*}
    FROM user_name [, user_name ...]

GRANT is implemented in MySQL Version 3.22.11 or later. For earlier MySQL versions, the GRANT statement does nothing.

The GRANT and REVOKE commands allow system administrators to create users and grant and revoke rights to MySQL users at four privilege levels:

Global level
Global privileges apply to all databases on a given server. These privileges are stored in the mysql.user table. REVOKE ALL ON *.* will revoke only global privileges.
Database level
Database privileges apply to all tables in a given database. These privileges are stored in the mysql.db and mysql.host tables. REVOKE ALL ON db.* will revoke only database privileges.
Table level
Table privileges apply to all columns in a given table. These privileges are stored in the mysql.tables_priv table. REVOKE ALL ON db.table will revoke only table privileges.
Column level
Column privileges apply to single columns in a given table. These privileges are stored in the mysql.columns_priv table. When using REVOKE you must specify the same columns that were granted.

For the GRANT and REVOKE statements, priv_type may be specified as any of the following:

ALL [PRIVILEGES] Sets all simple privileges except WITH GRANT OPTION
ALTER Allows usage of ALTER TABLE
CREATE Allows usage of CREATE TABLE
CREATE TEMPORARY TABLES Allows usage of CREATE TEMPORARY TABLE
DELETE Allows usage of DELETE
DROP Allows usage of DROP TABLE.
EXECUTE Allows the user to run stored procedures (MySQL 5.0)
FILE Allows usage of SELECT ... INTO OUTFILE and LOAD DATA INFILE.
INDEX Allows usage of CREATE INDEX and DROP INDEX
INSERT Allows usage of INSERT
LOCK TABLES Allows usage of LOCK TABLES on tables for which one has the SELECT privilege.
PROCESS Allows usage of SHOW FULL PROCESSLIST
REFERENCES For the future
RELOAD Allows usage of FLUSH
REPLICATION CLIENT Gives the right to the user to ask where the slaves/masters are.
REPLICATION SLAVE Needed for the replication slaves (to read binlogs from master).
SELECT Allows usage of SELECT
SHOW DATABASES SHOW DATABASES shows all databases.
SHUTDOWN Allows usage of mysqladmin shutdown
SUPER Allows one connect (once) even if max_connections is reached and execute commands CHANGE MASTER, KILL thread, mysqladmin debug, PURGE MASTER LOGS and SET GLOBAL
UPDATE Allows usage of UPDATE
USAGE Synonym for ``no privileges.''
GRANT OPTION Synonym for WITH GRANT OPTION

USAGE can be used when you want to create a user that has no privileges.

The privileges CREATE TEMPORARY TABLES, EXECUTE, LOCK TABLES, REPLICATION ..., SHOW DATABASES and SUPER are new for in version 4.0.2. To use these new privileges after upgrading to 4.0.2, you have to run the mysql_fix_privilege_tables script.

In older MySQL versions, the PROCESS privilege gives the same rights as the new SUPER privilege.

To revoke the GRANT privilege from a user, use a priv_type value of GRANT OPTION:

mysql> REVOKE GRANT OPTION ON ... FROM ...;

The only priv_type values you can specify for a table are SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, GRANT OPTION, INDEX, and ALTER.

The only priv_type values you can specify for a column (that is, when you use a column_list clause) are SELECT, INSERT, and UPDATE.

MySQL allows you to create database level privileges even if the database doesn't exist, to make it easy to prepare for database usage. Currently MySQL does however not allow one to create table level grants if the table doesn't exist. MySQL will not automatically revoke any privileges even if you drop a table or drop a database.

You can set global privileges by using ON *.* syntax. You can set database privileges by using ON db_name.* syntax. If you specify ON * and you have a current database, you will set the privileges for that database. (Warning: if you specify ON * and you don't have a current database, you will affect the global privileges!)

Please note: the `_' and `%' wildcards are allowed when specifying database names in GRANT commands. This means that if you wish to use for instance a `_' character as part of a database name, you should specify it as `\_' in the GRANT command, to prevent the user from being able to access additional databases matching the wildcard pattern, for example, GRANT ... ON `foo\_bar`.* TO ....

In order to accommodate granting rights to users from arbitrary hosts, MySQL supports specifying the user_name value in the form user@host. If you want to specify a user string containing special characters (such as `-'), or a host string containing special characters or wildcard characters (such as `%'), you can quote the user or host name (for example, 'test-user'@'test-hostname').

You can specify wildcards in the hostname. For example, user@'%.loc.gov' applies to user for any host in the loc.gov domain, and user@'144.155.166.%' applies to user for any host in the 144.155.166 class C subnet.

The simple form user is a synonym for user@"%".

MySQL doesn't support wildcards in user names. Anonymous users are defined by inserting entries with User='' into the mysql.user table or creating an user with an empty name with the GRANT command.

Note: if you allow anonymous users to connect to the MySQL server, you should also grant privileges to all local users as user@localhost because otherwise the anonymous user entry for the local host in the mysql.user table will be used when the user tries to log into the MySQL server from the local machine!

You can verify if this applies to you by executing this query:

mysql> SELECT Host,User FROM mysql.user WHERE User='';

For the moment, GRANT only supports host, table, database, and column names up to 60 characters long. A user name can be up to 16 characters.

The privileges for a table or column are formed from the logical OR of the privileges at each of the four privilege levels. For example, if the mysql.user table specifies that a user has a global SELECT privilege, this can't be denied by an entry at the database, table, or column level.

The privileges for a column can be calculated as follows:

global privileges
OR (database privileges AND host privileges)
OR table privileges
OR column privileges

In most cases, you grant rights to a user at only one of the privilege levels, so life isn't normally as complicated as above. The details of the privilege-checking procedure are presented in section 4.2 General Security Issues and the MySQL Access Privilege System.

If you grant privileges for a user/hostname combination that does not exist in the mysql.user table, an entry is added and remains there until deleted with a DELETE command. In other words, GRANT may create user table entries, but REVOKE will not remove them; you must do that explicitly using DELETE.

In MySQL Version 3.22.12 or later, if a new user is created or if you have global grant privileges, the user's password will be set to the password specified by the IDENTIFIED BY clause, if one is given. If the user already had a password, it is replaced by the new one.

If you don't want to send the password in clear text you can use the PASSWORD option followed by a scrambled password from SQL function PASSWORD() or the C API function make_scrambled_password(char *to, const char *password).

Warning: if you create a new user but do not specify an IDENTIFIED BY clause, the user has no password. This is insecure.

Passwords can also be set with the SET PASSWORD command. See section 5.5.6 SET Syntax.

If you grant privileges for a database, an entry in the mysql.db table is created if needed. When all privileges for the database have been removed with REVOKE, this entry is deleted.

If a user doesn't have any privileges on a table, the table is not displayed when the user requests a list of tables (for example, with a SHOW TABLES statement). The same is true for SHOW DATABASES.

The WITH GRANT OPTION clause gives the user the ability to give to other users any privileges the user has at the specified privilege level. You should be careful to whom you give the GRANT privilege, as two users with different privileges may be able to join privileges!

MAX_QUERIES_PER_HOUR #, MAX_UPDATES_PER_HOUR # and MAX_CONNECTIONS_PER_HOUR # are new in MySQL version 4.0.2. These options limit the number of queries/updates and logins the user can do during one hour. If # is 0 (default), then this means that there are no limitations for that user. See section 4.3.6 Limiting user resources. Note: to specify any of these options for an existing user without adding other additional privileges, use GRANT USAGE ON *.* ... WITH MAX_....

You cannot grant another user a privilege you don't have yourself; the GRANT privilege allows you to give away only those privileges you possess.

Be aware that when you grant a user the GRANT privilege at a particular privilege level, any privileges the user already possesses (or is given in the future!) at that level are also grantable by that user. Suppose you grant a user the INSERT privilege on a database. If you then grant the SELECT privilege on the database and specify WITH GRANT OPTION, the user can give away not only the SELECT privilege, but also INSERT. If you then grant the UPDATE privilege to the user on the database, the user can give away the INSERT, SELECT and UPDATE.

You should not grant ALTER privileges to a normal user. If you do that, the user can try to subvert the privilege system by renaming tables!

Note that if you are using table or column privileges for even one user, the server examines table and column privileges for all users and this will slow down MySQL a bit.

When mysqld starts, all privileges are read into memory. Database, table, and column privileges take effect at once, and user-level privileges take effect the next time the user connects. Modifications to the grant tables that you perform using GRANT or REVOKE are noticed by the server immediately. If you modify the grant tables manually (using INSERT, UPDATE, etc.), you should execute a FLUSH PRIVILEGES statement or run mysqladmin flush-privileges to tell the server to reload the grant tables. See section 4.3.3 When Privilege Changes Take Effect.

The biggest differences between the SQL standard and MySQL versions of GRANT are:

For a description of using REQUIRE, see section 4.3.9 Using Secure Connections.

User Comments

Posted by Frank Wortner on Saturday February 16 2002, @10:21pm[Delete] [Edit]

I had no problems with ld. DEC (Compaq) might
have fixed ld in a patch kit. You might want to
install the latest patch kit for your Digital Unix
(Tru64 Unix) before building MySQL. Patch kits
are available at
<a
href=http://ftp.support.compaq.com/public/unix/>
http://ftp.support.compaq.com/public/unix/</a>

Posted by rochlin on Saturday February 16 2002, @10:21pm[Delete] [Edit]

For source installations, these instructions refer to the directory structure presuming "usr/local" was used (default) with configure. But the preceding page's instructions (for compilation/installation) suggest you use:

./configure --prefix=/usr/local/mysql

To be consistent (and this is causing me some hassles with Perl, so it's not purely semantic), the instructions on this page should presume /usr/local/mysql was specified as the installation directory with configure.

Posted by Linda Wright on Saturday February 16 2002, @10:21pm[Delete] [Edit]

This is probably the most important and least
appreciated sections of all of the mySQL
documentation for first time mySQL users. IMHO,
reading this page in conjunction with
http://www.mysql.com/doc/P/r/Privileges.html is a
must for anyone planning secure database systems
of any real sophistication.

Posted by Christopher Raymond on Saturday February 16 2002, @10:21pm[Delete] [Edit]

I am trying to install MySQL under OS X Public Beta. When I run the mysql_install_db script, I get an error message:

dyld: ./bin/mysqld can't open library: /usr/lib/libpthread.A.dylib (No such file or directory, errno = 2)
Installation of grant tables failed!

I am assuming that the script is looking for a directory that doesn't exist because Apple has a little bit different directory naming structure. Maybe this script needs to be modified for the OS X distribution.

Can anyone help?

Posted by Mark Zieg on Saturday February 16 2002, @10:21pm[Delete] [Edit]

It would be nice if there was an option to log connections, but not queries.

Posted by Bennett Haselton on Saturday February 16 2002, @10:21pm[Delete] [Edit]

If you're logged on as the mysql root user, without a current database selected, and you try to
grant all privileges to a user with the command:

GRANT ALL PRIVILEGES ON * TO bhaselto

then the RELOAD, SHUTDOWN, PROCESS, FILE and GRANT will not be granted, as can be
verified by checking the "user" table of the "mysql" database. (This is presumably by design,
since these privileges can make a user "too powerful".)

Posted by DC Hill on Saturday February 16 2002, @10:21pm[Delete] [Edit]

NOTE: If you have granted privileges to a user on a particular database, or at any lower level than that, invoking "REVOKE ALL ON *.* FROM user@host;" will NOT revoke privileges at those levels. The *.* in the above statement means 'global', not 'all (individual) tables on all (individual) databases. That statment will ONLY revoke global privileges, as stored in the mysql.user table. You MUST revoke any more specific privileges in the same manner as they were granted, if you wish them to be removed from the privilege tables. (i.e. - GRANT ALL ON foo.* TO user@host; => REVOKE ALL ON foo.* FROM user@host;) I hope this saves some of you a little time and frustration.

Posted by Cris Perdue on Saturday February 16 2002, @10:21pm[Delete] [Edit]

REVOKE ALL on *.* from user@localhost does not revoke the privilege to connect to the database
server. To prohibit connections altogether it appears you have to use an SQL delete statement
then "flush privileges". This situation includes connection rights for the anonymous user
(""@localhost) automatically granted by some RPM distributions of MySQL. This usage of REVOKE
does remove all global privileges to do operations such as SELECT, INSERT, etc., leaving only the
privilege to connect.

Posted by Ken Maupin on Saturday February 16 2002, @10:21pm[Delete] [Edit]

The documentation doesn't emphasize this point,
but it appears tables_priv doesn't allow CIDR
notation in the Host column. If you use CIDR
notation in the other privilege tables, you need
to use wildcard notation in tables_priv. This
also affects the way GRANT and REVOKE work: if you
grant table-specific privileges to a user using
CIDR notation, you'll need to manually adjust the
Host column in tables_priv.

Posted by Antonius Jacobs on Saturday February 16 2002, @10:21pm[Delete] [Edit]

I just chanced my password in mysql now I can't
login anymore. I have used the mysql usermanuel.
I hope someone can help my with this problem.

Posted by Sania Prokopyuk on Saturday February 16 2002, @10:21pm[Delete] [Edit]

To enable REPLACE command you have to set the
user DELETE privilegy!

Posted by William Janoch on Saturday February 16 2002, @10:21pm[Delete] [Edit]

For detailed exples of how to use GRANT, check out the GRANT OPTIONS section of the documentation.

Here's a pretty standard GRANT to give a use control of a whole (single) database:
GRANT ALL ON database.* TO user IDENTIFIED BY "password"

Posted by William Janoch on Wednesday December 18 2002, @5:27pm[Delete] [Edit]

Common General GRANT examples to give "user" total control of a single database:

from localhost:GRANT ALL ON database.* TO user@localhost IDENTIFIED BY "password"
from remote host: GRANT ALL ON database.* TO user@example.com IDENTIFIED BY "password"

Posted by Joel Dare on Saturday February 16 2002, @10:21pm[Delete] [Edit]

Don't forget to "flush privileges"! I just spent
a couple hours trying to figure out why I
couldn't load a file after granting the
appropriate permissions...

Posted by ute.diestel on Saturday February 16 2002, @10:21pm[Delete] [Edit]

!!! Process_priv=N does not generally mean NOT,

also:

4.5.6.6 SHOW PROCESSLIST
http://www.mysql.com/doc/S/H/SHOW_PROCESSLIST.html

"If you have the process privilege, you can see
all threads.
Otherwise, you can see only your own threads."

Posted by FreeBSD Forums on Saturday February 16 2002, @10:21pm[Delete] [Edit]

You can use phpMyAdmin web based tool to do a lot
of mySQL admin functions. <a
href="http://www.freebsdforums.org"
>FreeBSD forums</a>

Posted by [name withheld] on Monday February 25 2002, @6:03am[Delete] [Edit]

Verified on MySQL 3.23.36 on Red Hat Linux 7.1:
Note that if you type
use a_c;
grant select on * to user@host;
you will have given user@host access to any
database matching 'a_c' where the underscore is a
wildcard. (Rarely a problem, I suppose).
Rectify with
update mysql.db set db='a\_c' where db='a_c';

Posted by jan behrens on Tuesday July 9 2002, @1:31am[Delete] [Edit]

the aformentioned bug from DAN ELIN in x.x.41 is
apperently still valid in x.x.51,i cannot logon to a
database after GRANTing privileges and given a
password to a new user(yes, i flushed
privileges)...................only root access is possible

Posted by Dan Egli on Thursday April 4 2002, @8:33pm[Delete] [Edit]

There seems to be a bug in 3.23.41 using Grant.
Only root can access the mysql database, even
after using Grant to grant privs on whatever
database/table/column/ect.. you always get
permission denied, regardless.

Posted by Lars Aronsson on Saturday June 8 2002, @11:16am[Delete] [Edit]

The normal response from a grant or revoke
statement is "Query OK, 0 rows affected". The
message that zero rows were affected is a common
source of confusion, but should just be ignored by
the user. Trying to revoke grants that were never
granted yields an "ERROR 1147: There is no such
grant defined for user...".

Posted by Marcio Merlone on Monday June 10 2002, @2:08pm[Delete] [Edit]

Where can I find information on how to revoke the
rights to 'show databases' command for ordinary
users? I donīt want my users to know wich
databases exists on server...

Posted by Eric Anderson on Tuesday June 11 2002, @9:40am[Delete] [Edit]

I'm attempting to delete two users, one called
webmaster@"localhost" and the other
webmaster@"%". When I try to delete them I'm told
error: 1066: not unique table/alias and when I
try to specify by their ip mask I get a syntax
error. Any suggestions?

Posted by Philip Mak on Wednesday December 18 2002, @5:27pm[Delete] [Edit]

Eric Anderson wrote:
&gt; I'm attempting to delete two users, one called webmaster@"localhost" and the other webmaster@"%".

Try this:
<tt>DELETE FROM user WHERE user='webmaster' AND host='localhost';
DELETE FROM user WHERE user='webmaster' AND host='%';
FLUSH PRIVILEGES;

Posted by Melvyn Sopacua on Monday August 19 2002, @5:15am[Delete] [Edit]

For 4.0.2, the privilege system has changed with
some backwards compatibility concerns, even when
the mysql_fix_privileges script has been run.

If you have a user, with all privileges for a
certian database, but no global privileges, the
CREATE TEMPORARY TABLE privilege on that database
is denied.

You have to give global CREATE __and__ global
CREATE TEMPORARY TABLES to the user. IOW:
GRANT CREATE, CREATE TEMPORARY TABLES ON *.* TO
user@host;

Needless to say, this affects security grately.

Posted by [name withheld] on Sunday August 25 2002, @9:17am[Delete] [Edit]

Temporary files are a great idea but even with
Create and Create Temproary File rights in the
user (global rights) file it still doesn't work.
This appears to be badly designed.

Posted by Brad Bulger on Monday September 2 2002, @4:09am[Delete] [Edit]

It should be noted that WITH GRANT OPTION only
allows the user to pass on privileges to users who
already exist. The automagical creation of user
records does not apply - you get an error saying
that the user with the GRANT OPTION privilege does
not have access to the 'mysql' database. This is
probably a good thing, but it needs to be documented.

Posted by Michael Babcock on Friday November 8 2002, @1:00pm[Delete] [Edit]

SHOW MASTER STATUS requires PROCESS privileges.
Other such odd combinations should be documented.

Posted by Dee Kintaudi on Thursday November 21 2002, @12:42pm[Delete] [Edit]

Okay I got a question and a problem with Mysql and
passwords:). I tried to use several of the options
and most of them have not worked. However one
soloution did work and I tested it out twice and it
was solid. Of course I lost the little piece of paper I
wrote it out on and I can't seem to find this
soloution anywhere, as if it did not exist or maybe I
imagined it. The soloution that worked for me,
before I lost the little slip of paper I wrote it down on
goes something like this..... Insert into user root
Password "my password" and then something
with 'Y', 'Y', 'Y', (about a dozen or 15 times or so)
However, I can not find this soloution anywhere can
someone help me out here?

I think it would be so nice if they just put this
throughout their documentation instead of trying to
hide it. I think this would solve many problems. Just
put password = 'Y', 'Y', 'Y', its like their ashamed of it
or something.

Posted by AJIT DIXIT on Monday November 25 2002, @6:56am[Delete] [Edit]

When I work on multi-table update with root user
it works fine

When I work with non-root user I get error

Sql : update Stockists, areas set a_nm = aname
where acd = area

Error : update command denied to user:
'aldixit@localhost' for table 'areas'

What previledges are required for multi-table update ?

Posted by Martin Francis on Thursday March 27 2003, @8:49am[Delete] [Edit]

Version 3.23.38 for Windows: Hyphens in database names

If the database you are granting access to has a hyphen in the name, use backticks around the database name or the command will fail:

GRANT Select, Insert, Update, Delete, Index, Alter, Create, Drop, References
ON `test-1`.*
TO 'user-1'@'%'
IDENTIFIED BY 'secret'

Posted by lee chau on Wednesday March 12 2003, @10:05am[Delete] [Edit]

Is it possible to create an user account with say all privileges on all database EXCEPT mysql database, and no need to further update this acount's privileges even a new database is created later on ?

Posted by Rizwan Omer on Sunday April 13 2003, @1:26am[Delete] [Edit]

A simple example to Create a user with Administriative right will be:

mysql> GRANT ALL PRIVILEGES ON *.* TO myNewAdminUser@localhost
-> IDENTIFIED BY 'myAdminPassword' WITH GRANT OPTION;

where myNewAdminUser is the name of the new User to be created and
myAdminPassword is the password for the new Admin User.

Hope it helps...Cheers!

Posted by ratha grimes on Wednesday June 25 2003, @7:20pm[Delete] [Edit]

If you create a database with a mixed case name (e.g. "MySqlTestDatabase") and then try to assign rights to a user for that database ("grant all on MySqlTestDatabase.* to user@localhost"), your user will not be able to access the db. That's because the create database statement will ignore the lettercase and name your database with lowercase letters, but the grant statement will respect the case and insert into the "mysql.db" privilege table with the case as given. Then when your user tries to access the database, they won't be allowed, because the privilege doesn't match the actual database name. To fix it, rectify the db table: "update db set database = 'mysqltestdatabase' where database = 'MySqlTestDatabase'." (Don't forget to "flush privileges.")

Posted by [name withheld] on Saturday July 19 2003, @1:39am[Delete] [Edit]

I tried to 'grant' all priveleges for a new user (in fact creating this user with all rights already given) with the following statement:
mysql> INSERT INTO user VALUES ('localhost', 'thenewuser', PASSWORD('newuserspwd'),
-> 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y',
-> 'Y');
And it all worked. I guess you must be very confident about someone when giving him/her access to the 'user' table because it means that a new user can be added with ALL the priveleges!

Add your own comment.