Vous êtes sur la page 1sur 8

MYSQL

An introduction to MySQL permissions


By Ian Gilfillan
Posted Feb 17, 2004
http://www.databasejournal.com/features/mysql/article.php/3311731/An-introductio
n-to-MySQL-permissions.htm
Edited by #SMA 29 julio 2015
MySQL newbies often have problems with the MySQL access control system. But once
you get used to it, I think you will find it flexible and easy to use, so this
month we're going to examine how to get started with MySQL permissioning.
The USER table
MySQL access is controlled by the mysql database. Let's take a look at the table
s found in this database. The following list comes from MySQL 5 - earlier versio
ns of MySQL will be different, but in this tutorial I only focus on those tables
available to the current stable version 4.0.x
mysql> SHOW TABLES;
+-----------------+
| Tables_in_mysql |
+-----------------+
| columns_priv
|
| db
|
| func
|
| help_category |
| help_keyword
|
| help_relation |
| help_topic
|
| host
|
| proc
|
| tables_priv
|
| user
|
+-----------------+
When a user tries to connect to the database, MySQL checks that that particular
username/host/password combination has permission to connect. Once the connectio
n has been made, before any operations are carried out, MySQL again checks to se
e whether the user/host combination has the right level of access to carry out t
hat operation. The user table is the first table MySQL checks. All user/host/pas
sword combinations must be listed in this table before any access can be granted
. Let's look at the table in more detail:
mysql> DESC user;
+-----------------+---------------+------+-----+---------+-------+
| Field
| Type
| Null | Key | Default | Extra |
+-----------------+---------------+------+-----+---------+-------+
| Host
| char(60)
|
| PRI |
|
|
| User
| char(16)
|
| PRI |
|
|
| Password
| char(16)
|
|
|
|
|
| Select_priv
| enum('N','Y') |
|
| N
|
|
| Insert_priv
| enum('N','Y') |
|
| N
|
|
| Update_priv
| enum('N','Y') |
|
| N
|
|
| Delete_priv
| enum('N','Y') |
|
| N
|
|
| Create_priv
| enum('N','Y') |
|
| N
|
|

| Drop_priv
| enum('N','Y') |
|
| N
|
|
| Reload_priv
| enum('N','Y') |
|
| N
|
|
| Shutdown_priv | enum('N','Y') |
|
| N
|
|
| Process_priv
| enum('N','Y') |
|
| N
|
|
| File_priv
| enum('N','Y') |
|
| N
|
|
| Grant_priv
| enum('N','Y') |
|
| N
|
|
| References_priv | enum('N','Y') |
|
| N
|
|
| Index_priv
| enum('N','Y') |
|
| N
|
|
| Alter_priv
| enum('N','Y') |
|
| N
|
|
+-----------------+---------------+------+-----+---------+-------+
It is important to understand that the host and user together determine an indiv
idual permission for connecting. User Nosipho may have access from host A, and n
ot from host B. In fact, user Nosipho on host B may be an entirely different use
r.
A host may be either the hostname of the machine, or the IP, and may be, or incl
ude, a wildcard (the % sign), meaning any host. It should be rare to allow acces
s from any host. Web applications, for example, typically only allow access to t
he database server from the web server (or localhost for small setups, where the
y're on the same machine). The password is stored in an encrypted format using t
he PASSWORD() function. Let's look at a sample subset from the user table:
mysql> SELECT host,user FROM user;
+---------------+------+
| host
| user |
+---------------+------+
| localhost
| mysql|
| localhost
| mark |
| 192.168.5.42 | tiki |
| 192.168.5.% | mpho |
| 192.168.5.42 |
|
| %
| wiki |
+---------------+------+
In this example, the mysql and mark users can connect from localhost only, while
user tiki, and any other user, can connect from the IP 192.168.5.42. User mpho
can connect from any IP starting with 192.168.5 (as denoted by the wildcard wher
e the last digit would be). Finally, user wiki has access from any machine. This
does not necessarily mean they can do anything, just that they can connect.
To decide whether a user has access to perform a particular operation, MySQL aga
in checks the user table first. The remaining fields, all fairly clearly named,
come into play. Select_priv determines whether users can run SELECT queries, Ins
ert_priv INSERT queries, and so on.
Permission

Description

Select_priv
Insert_priv
Update_priv
Delete_priv
Create_priv
Drop_priv
Reload_priv
mple)
Shutdown_priv
Process_priv
File_priv
FILE)

Permission
Permission
Permission
Permission
Permission
Permission
Permission

to
to
to
to
to
to
to

run SELECT queries


run INSERT statements
run UPDATE statements
run DELETE statements
CREATE tables and databases
DROP tables and databases
RELOAD the database (a FLUSH statement for exa

Permission to SHUTDOWN the database server


Permission to view or kill PROCESSes.
Permission to read and write FILEs (for example LOAD DATA IN

Grant_priv
References_priv
Index_priv
Alter_priv

Permission to GRANT available permissions to other users


Permissions to create, modify or drop INDEXes
Not used by MySQL 4.0.x
Permission to ALTER table structures.

All are enumerated types, a Y value allowing the operation, and a N value possib
ly disallowing it. Only possibly, because the user table is the bluntest kind of
permission. A Y value in one of these fields always allows that operation to be
performed on all databases in the table. It is often good practice to set value
s to N in the user table, and then allow them for the appropriate database only,
as we'll see now. Another sample:
mysql> SELECT host,user,select_priv,insert_priv FROM user;
+-----------+------+-------------+-------------+
| host
| user | select_priv | insert_priv |
+-----------+------+-------------+-------------+
| %
| mark | Y
| N
|
| localhost | mpho | N
| N
|
+-----------+------+-------------+-------------+
Here user mark can always perform SELECT queries, while for the other operations
, MySQL will need to check the other tables first to see, starting with the db t
able.
The DB table
If the user table allows access, but disallows permission for a particular opera
tion, the next table to worry about is the db table. This sets permissions for s
pecific databases.
mysql> DESC db;
+-----------------+---------------+------+-----+---------+-------+
| Field
| Type
| Null | Key | Default | Extra |
+-----------------+---------------+------+-----+---------+-------+
| Host
| char(60)
|
| PRI |
|
|
| Db
| char(32)
|
| PRI |
|
|
| User
| char(16)
|
| PRI |
|
|
| Select_priv
| enum('N','Y') |
|
| N
|
|
| Insert_priv
| enum('N','Y') |
|
| N
|
|
| Update_priv
| enum('N','Y') |
|
| N
|
|
| Delete_priv
| enum('N','Y') |
|
| N
|
|
| Create_priv
| enum('N','Y') |
|
| N
|
|
| Drop_priv
| enum('N','Y') |
|
| N
|
|
| Grant_priv
| enum('N','Y') |
|
| N
|
|
| References_priv | enum('N','Y') |
|
| N
|
|
| Index_priv
| enum('N','Y') |
|
| N
|
|
| Alter_priv
| enum('N','Y') |
|
| N
|
|
+-----------------+---------------+------+-----+---------+-------+
Host and User appear in the same way in this table, but attached to a database,
not a password. The same host/user combination appears, with a password, in the
user table, which allows the user to connect, but if they do not have permission
to perform an operation, MySQL will check this table to see if they can perform
it on a particular database. A sample:
mysql> SELECT host,db,user,select_priv,insert_priv FROM db;
+-----------+----------+-------+-------------+-------------+
| host
| db
| user | select_priv | insert_priv |
+-----------+----------+-------+-------------+-------------+
| localhost | news
| mark | Y
| Y
|

| localhost | archives | mpho | N


| N
|
| localhost | news
| mpho | Y
| Y
|
+-----------+----------+-------+-------------+-------------+
Compare this with the previous sample we looked at from the user table. User mar
k already had Select permission on all databases, but no Insert permissions. Her
e, he is granted insert permission on the news database only, while user mpho is
given select and insert permission on the news database. Most MySQL installatio
ns in any kind of multi-user scenario would be best served by denying global per
missions, and granting them on the database-level only.
Another possibility exists. The database and user combination were found, but th
e host was left blank. In this case, MySQL checks the host table. Let's look at
what's in there:
mysql> DESC host;
+-----------------+---------------+------+-----+---------+-------+
| Field
| Type
| Null | Key | Default | Extra |
+-----------------+---------------+------+-----+---------+-------+
| Host
| char(60)
|
| PRI |
|
|
| Db
| char(32)
|
| PRI |
|
|
| Select_priv
| enum('N','Y') |
|
| N
|
|
| Insert_priv
| enum('N','Y') |
|
| N
|
|
| Update_priv
| enum('N','Y') |
|
| N
|
|
| Delete_priv
| enum('N','Y') |
|
| N
|
|
| Create_priv
| enum('N','Y') |
|
| N
|
|
| Drop_priv
| enum('N','Y') |
|
| N
|
|
| Grant_priv
| enum('N','Y') |
|
| N
|
|
| References_priv | enum('N','Y') |
|
| N
|
|
| Index_priv
| enum('N','Y') |
|
| N
|
|
| Alter_priv
| enum('N','Y') |
|
| N
|
|
+-----------------+---------------+------+-----+---------+-------+
Exactly the same kind of checks occur here. An example:
mysql> SELECT host,db,select_priv,insert_priv FROM host;
+---------------+----------+-------------+-------------+
| host
| db
| select_priv | insert_priv |
+---------------+----------+-------------+-------------+
| localhost
| news
| Y
| Y
|
| localhost
| archives | Y
| N
|
| 192.168.5.42 | news
| Y
| N
|
+---------------+----------+-------------+-------------+
If the host had been left blank, permissions are determined here. A user from lo
calhost would have both select and insert permission to the news database, while
a user from the host 192.168.5.42 would only have select permission to this dat
abase. From localhost, a user would have select privileges only on the archives
database.
But there is still more fine-tuning possible. You can assign users permission on
a table, or even a column level, with the tables_priv and columns_priv tables,
described below:
mysql> DESC tables_priv;
+-------------+---------------------------------------------------+------+-----+
---------+-------+
| Field
| Type
| Null | Key |
Default | Extra |
+-------------+---------------------------------------------------+------+-----+

---------+-------+
| Host
| char(60)
|
| PRI |
|
|
| Db
| char(60)
|
| PRI |
|
|
| User
| char(16)
|
| PRI |
|
|
| Table_name | char(60)
|
| PRI |
|
|
| Grantor
| char(77)
|
| MUL |
|
|
| Timestamp | timestamp(14)
| YES |
|
NULL
|
|
| Table_priv | set('Select','Insert','Update','Delete','Create', |
|
|
|
|
|
|'Drop','Grant','References','Index','Alter')
|
|
|
|
|
| Column_priv | set('Select','Insert','Update','References')
|
|
|
|
|
+-------------+---------------------------------------------------+------+-----+
---------+-------+
mysql> DESC columns_priv;
+-------------+----------------------------------------------+------+-----+--------+-------+
| Field
| Type
| Null | Key | Defa
ult | Extra |
+-------------+----------------------------------------------+------+-----+--------+-------+
| Host
| char(60)
|
| PRI |
|
|
| Db
| char(60)
|
| PRI |
|
|
| User
| char(16)
|
| PRI |
|
|
| Table_name | char(60)
|
| PRI |
|
|
| Column_name | char(60)
|
| PRI |
|
|
| Timestamp | timestamp(14)
| YES |
| NULL
|
|
| Column_priv | set('Select','Insert','Update','References') |
|
|
|
|
+-------------+----------------------------------------------+------+-----+--------+-------+
A brief recap of the process
The order of precedence of the tables is as follows:
user: User accounts, global privileges, and other non-privilege columns.
db: Database-level privileges.
host: Obsolete. MySQL install operations do not create this table as of MySQ
L 5.6.7.
tables_priv: Table-level privileges.

columns_priv: Column-level privileges.


procs_priv: Stored procedure and function privileges.
proxies_priv: Proxy-user privileges.
MySQL checks the user table first, if permission is not granted there, it will c
heck the db and host tables, and, if further confirmation is required, the table
s_priv and even the columns_priv tables. Be aware that excessive use of all thes
e tables comes at a performance cost - if before every operation MySQL has to ch
eck permissions at a column level, it will be that much slower. Use what you nee
d, no more, no less.
How to GRANT permissions
Hopefully the process has been easy to follow, but the burning question must be,
how does anyone set these permissions! There are two ways - directly manipulati
ng the tables, with INSERT, UPDATE and DELETE statements (which require MySQL to
be reloaded, or the privileges flushed, for example with the FLUSH PRIVILEGES s
tatement. Note also that if you add a record directly to the password field in t
he user table, you must use the PASSWORD() function. The alternative, more conve
nient in my opinion, is using a GRANT statement. The syntax of a GRANT statement
is:
GRANT privilege ON table_or_database_name TO user@hostname IDENTIFIED BY 'pa
ssword'.
The privileges are:
Privilege

Description

ALL/ALL PRIVILEGES
All the basic permissions
ALTER
Permission to run ALTER statements
CREATE
Permission to CREATE tables or databases
CREATE TEMPORARY TABLES Permission to run CREATE TEMPORARY TABLE statements
DELETE
Permission to run DELETE statements
DROP
Permission to DROP tables or databases
EXECUTE
Permission to run stored procedures (in MySQL 5)
FILE
Permission to read and write files (e.g. LOAD DATA I
NFILE statements)
GRANT
Permission to GRANT available permissions to other u
sers
INDEX
Permission to create, change or drop indexes
INSERT
Permission to run INSERT statements
LOCK TABLES
Permission to LOCK tables which the user has SELECT
access to
PROCESS
Permission to view or kill MySQL processes
REFERENCES
Currently unused
RELOAD
Permission to reload the database (e.g. FLUSH statem
ents)
REPLICATION CLIENT
Permission to ask about replication
REPLICATION SLAVE
Permission to replicate from the server
SHOW DATABASES
Permission to see all databases
SELECT
Permission to run SELECT statements
SHUTDOWN
Permission to SHUTDOWN the MySQL server
SUPER
Permission to connect, even if the number of connect
ions is exceeded, and perform maintenance commands
UPDATE
Permission to run UPDATE statements
USAGE
Permission to connect and and perform basic commands
only

Database and Table names in a GRANT statement


Name

Description

*.*
*
dbname.*
dbname.tbname

All
All
All
The

tables in all databases


tables in the current database
tables in the named database
named table in the named database

So, some examples of GRANT in action:


mysql> GRANT SELECT ON *.* TO rushdi@localhost IDENTIFIED BY 'supa_password'
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT host,user,password,select_priv,insert_priv FROM user WHERE user =
'rushdi';
+-----------+--------+------------------+-------------+-------------+
| host
| user | password
| select_priv | insert_priv |
+-----------+--------+------------------+-------------+-------------+
| localhost | rushdi | 0b3bcd316f1c8020 | Y
| N
|
+-----------+--------+------------------+-------------+-------------+
Note that the password has been automatically encrypted. The record also only ap
pears in the user table, not the db table, as permission was granted to all data
bases. Another example:
mysql> GRANT INSERT ON mysql.* TO suretha@localhost IDENTIFIED BY 'supa_password
2';
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT host,user,password,select_priv,insert_priv FROM user WHERE user =
'Suretha';
+-----------+---------+------------------+-------------+-------------+
| host
| user
| password
| select_priv | insert_priv |
+-----------+---------+------------------+-------------+-------------+
| localhost | suretha | 30f59c271b923c47 | N
| N
|
+-----------+---------+------------------+-------------+-------------+
mysql> SELECT host,db,user,select_priv,insert_priv FROM db WHERE user='Suretha';
+-----------+-------+---------+-------------+-------------+
| host
| db
| user
| select_priv | insert_priv |
+-----------+-------+---------+-------------+-------------+
| localhost | mysql | suretha | N
| Y
|
+-----------+-------+---------+-------------+-------------+
Here records are added to both the user and db tables. To revoke permission, we
use the REVOKE statement.
mysql> REVOKE SELECT ON *.* FROM rushdi@localhost;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT host,user,password,select_priv,insert_priv FROM user WHERE user =
'rushdi';
+-----------+--------+------------------+-------------+-------------+
| host
| user | password
| select_priv | insert_priv |
+-----------+--------+------------------+-------------+-------------+
| localhost | rushdi | 0b3bcd316f1c8020 | N
| N
|
+-----------+--------+------------------+-------------+-------------+

Note that the record still appears in the table, so he can connect, but select_p
riv has been disabled.
mysql> REVOKE INSERT ON mysql.* FROM suretha@localhost;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT host,db,user,select_priv,insert_priv FROM db WHERE user='Suretha';
Empty set (0.00 sec)
mysql> SELECT host,user,password,select_priv,insert_priv FROM user WHERE user =
'Suretha';
+-----------+---------+------------------+-------------+-------------+
| host
| user
| password
| select_priv | insert_priv |
+-----------+---------+------------------+-------------+-------------+
| localhost | suretha | 30f59c271b923c47 | N
| N
|
+-----------+---------+------------------+-------------+-------------+
The record has been deleted from the db table, but still appears, with no permis
sions, in the user table.
Hopefully you're starting to find MySQL permissions flexible and easy to use. Al
though there is much more to explore, do not overuse the available options. You
will make management more complex, and affect performance. Good luck!

Vous aimerez peut-être aussi