MySQL has an advanced but non-standard security/privilege system. This section describes how it works.
The primary function of the MySQL privilege system is to associate a user name on a host with select, insert, update and delete privileges on a database.
Additional functionality includes the ability to have an anonymous user and
to grant privileges for MySQL-specific functions such as LOAD
DATA INFILE and administrative operations.
Please note that user names, as used by MySQL for
authentication purposes, have nothing to do with Unix user names (login
names) or Windows user names. Most MySQL clients try to log
in using the current Unix user name as the MySQL user name, but
that is for convenience only. Client programs allow a different name to
be specified with the -u or --user options. This means
that you can't make a database secure in any way unless all
MySQL user names have passwords. Anyone may attempt to connect
to the server using any name, and they will succeed if you don't have a
password for each name.
MySQL user names can be up to 16 characters long, whereas Unix user names typically are limited to 8 characters.
MySQL passwords have nothing to do with Unix passwords, either. There is no necessary connection between the password you use to log in on a Unix machine and the password you use to access a database on that machine. MySQL also encrypts passwords using a different algorithm than the one used during the Unix login process.
MySQL client programs generally require that you specify connection
parameters: the host you want to connect to, your user name and your
password. For example, the mysql client can be started like this
(optional arguments are enclosed between `[' and `]'):
shell> mysql [-h host_name] [-u user_name] [-pyour_pass]
Note that there is no space between -p and the password following it.
Alternate forms of the -h, -u and -p options are
--host=host_name, --user=user_name and
--password=your_pass.
mysql uses default values for connection parameters that are missing
from the command line. The default hostname is localhost and the
default user name is your Unix login name. (No password is supplied if
-p is missing.) Thus, for a Unix user joe, the following
commands are equivalent:
shell> mysql -h localhost -u joe shell> mysql -h localhost shell> mysql -u joe shell> mysql
Other MySQL clients behave similarly.
On Unix systems, you can specify different default values to be used when you make a connection, so that you need not enter them on the command line each time you invoke a client program:
[client] section of the
`.my.cnf' configuration file in your home directory. The relevant
section of the file might look like this:
[client] host=host_name user=user_name password=your_passSee section 4.15.4 Option files.
MYSQL_HOST. The MySQL user name can be
specified using USER, LOGNAME or LOGIN (although these
variables might already be set to your Unix login name, and it may be wise
not to change them). The password can be specified using MYSQL_PWD
(but this is insecure; see next section).
If connection parameters are specified in multiple ways, values specified on the command line override values specified in configuration files and environment variables, and values in configuration files override values in environment variables.
It is inadvisable to specify your password in a way that exposes it to discovery by other users. The methods you can use to specify your password when you run client programs are listed below, along with an assessment of the risks of each method:
-pyour_pass or --password=your_pass option on the command
line. This is convenient but insecure, since your password becomes visible
to system status programs (such as ps) that may be invoked by other
users to display command lines. (MySQL clients typically overwrite
the command line argument with zeroes during their initialization sequence,
but there is still a brief interval during which the value is visible.)
-p or --password option (with no your_pass value
specified). In this case, the client program solicits the password from
the terminal:
shell> mysql -u user_name -p Enter password: ********The client echoes `*' characters to the terminal as you enter your password so that onlookers cannot see it. It is more secure to enter your password this way than to specify it on the command line because it is not visible to other users. However, this method of entering a password is unsuitable if you want to invoke a client from a script that runs non-interactively.
[client] section of the `.my.cnf' file in your
home directory:
[client] password=your_passIf you store your password in `.my.cnf', the file should not be group or world readable or writable. Make sure the file's access mode is
400
or 600.
See section 4.15.4 Option files.
MYSQL_PWD environment variable, but
this method must be considered extremely insecure and should not be used.
Some versions of ps include an option to display the environment of
running processes; your password will be in plain sight for all to see if
you set MYSQL_PWD. Even on systems without such a version of
ps, it is unwise to assume there is no other method to observe process
environments.
All in all, the safest methods are probably to have the client program prompt for the password or to specify the password in a properly-protected `.my.cnf' file.
Privilege information is stored in the user, db, host,
tables_priv and columns_priv tables in the mysql
database (that is, in the database named mysql). The MySQL
server reads the contents of these tables when it starts up and under the
circumstances indicated in section 6.7 When privilege changes take effect.
The names used in this manual to refer to the privileges provided by MySQL are shown below, along with the table column name associated with each privilege in the grant tables and the context in which the privilege applies:
| Privilege | Column | Context |
| select | Select_priv | tables |
| insert | Insert_priv | tables |
| update | Update_priv | tables |
| delete | Delete_priv | tables |
| index | Index_priv | tables |
| alter | Alter_priv | tables |
| create | Create_priv | databases, tables or indexes |
| drop | Drop_priv | databases or tables |
| grant | Grant_priv | databases or tables |
| reload | Reload_priv | server administration |
| shutdown | Shutdown_priv | server administration |
| process | Process_priv | server administration |
| file | File_priv | file access on server |
The select, insert, update and delete privileges allow you to perform operations on rows in existing tables in a database.
SELECT statements require the select privilege only if they
actually retrieve rows from a table. You can execute certain SELECT
statements even without permission to access any of the databases on the
server. For example, you could use the mysql client as a simple
calculator:
mysql> SELECT 1+1; mysql> SELECT PI()*2;
The index privilege allows you to create or drop (remove) indexes.
The alter privilege allows you to use ALTER TABLE.
The create and drop privileges allow you to create new databases and tables, or to drop (remove) existing databases and tables.
Note that if you grant the drop privilege for the mysql
database to a user, that user can drop the database in which the
MySQL access privileges are stored!
The grant privilege allows you to give to other users those privileges you yourself possess.
The file privilege gives you permission to read and write files on
the server using the LOAD DATA INFILE and SELECT ... INTO
OUTFILE statements. Any user to whom this privilege is granted can read or
write any file that the MySQL server can read or write.
The remaining privileges are used for administrative operations, which are
performed using the mysqladmin program. The table below shows which
mysqladmin commands each administrative privilege allows you to
execute:
| Privilege | Commands permitted to privilege holders |
| reload | reload, refresh,
flush-privileges,
flush-hosts, flush-logs, flush-tables
|
| shutdown | shutdown
|
| process | processlist, kill
|
The reload command tells the server to reread the grant tables. The
refresh command flushes all tables and opens and closes the log
files. flush-privileges is a synonym for reload. The other
flush-* commands perform functions similar to refresh but are
more limited in scope, and may be preferable in some instances. For example,
if you want to flush just the log files, flush-logs is a better choice
than refresh.
The shutdown command shuts down the server.
The processlist command displays information about the threads
executing within the server. The kill command kills server threads.
You can always display or kill your own threads, but you need the
process privilege to display or kill threads initiated by other
users.
Certain privileges should be granted sparingly:
SELECT.
mysql database can be used to change passwords and
other access privilege information. (Even though passwords are stored
encrypted, a malicious user can, with sufficient privileges, replace a
password with a different one.)
There are some things that you cannot do with the MySQL privilege system:
The MySQL privilege system ensures that all users may do exactly the things that they are supposed to be allowed to do. When you connect to a MySQL server, your identity is determined by the host from which you connect and the user name you specify. The system grants privileges according to your identity and what you want to do.
MySQL considers both your hostname and user name in identifying you
because there is little reason to assume that a given user name belongs to
the same person everywhere on the Internet. For example, the user
bill who connects from whitehouse.gov need not be the same
person as the user bill who connects from microsoft.com.
MySQL handles this by allowing you to distinguish users on different
hosts that happen to have the same name: you can grant bill one set
of privileges for connections from whitehouse.gov, and a different set
of privileges for connections from microsoft.com.
MySQL access control involves two stages:
The server uses the user, db and host tables in the
mysql database at both stages of access control. The fields in these
grant tables are shown below:
| Table name | user | db | host
|
| Scope fields | Host | Host | Host
|
User | Db | Db
| |
Password | User | ||
| Privilege fields | Select_priv | Select_priv | Select_priv
|
Insert_priv | Insert_priv | Insert_priv
| |
Update_priv | Update_priv | Update_priv
| |
Delete_priv | Delete_priv | Delete_priv
| |
Index_priv | Index_priv | Index_priv
| |
Alter_priv | Alter_priv | Alter_priv
| |
Create_priv | Create_priv | Create_priv
| |
Drop_priv | Drop_priv | Drop_priv
| |
Grant_priv | Grant_priv | Grant_priv
| |
Reload_priv | |||
Shutdown_priv | |||
Process_priv | |||
File_priv |
For the second stage of access control (request verification), the server
may, if the request involves tables, additionally consult the
tables_priv and columns_priv tables. The fields in these
tables are shown below:
| Table name | tables_priv | columns_priv
|
| Scope fields | Host | Host
|
Db | Db
| |
User | User
| |
Table_name | Table_name
| |
Column_name
| ||
| Privilege fields | Table_priv | Type
|
Column_priv | ||
| Other fields | Timestamp | Timestamp
|
Grantor |
Each grant table contains scope fields and privilege fields.
Scope fields determine the scope of each entry in the tables, i.e., the
context in which the entry applies. For example, a user table entry
with Host and User values of 'thomas.loc.gov' and
'bob' would be used for authenticating connections made to the server
by bob from the host thomas.loc.gov. Similarly, a db
table entry with Host, User and Db fields of
'thomas.loc.gov', 'bob' and 'reports' would be used when
bob connects from the host thomas.loc.gov to access the
reports database. The tables_priv and columns_priv
tables contain scope fields indicating tables or table/column combinations
to which each entry applies.
For access-checking purposes, comparisons of Host values are
case insensitive. User, Password, Db and
Table_name values are case sensitive.
Column_name values are case insensitive in MySQL 3.22.12
and up (but case sensitive in 3.22.11).
Privilege fields indicate the privileges granted by a table entry, that is, what operations can be performed. The server combines the information in the various grant tables to form a complete description of a user's privileges. The rules used to do this are described in section 6.6 Access control, stage 2: Request verification.
Scope fields are strings, declared as shown below; the default value for each is the empty string:
| Field name | Type | |
Host | CHAR(60)
| |
User | CHAR(16)
| |
Password | CHAR(16)
| |
Db | CHAR(64) | (CHAR(60) for the
tables_priv and columns_priv tables)
|
In the user, db and host tables,
all privilege fields are declared as ENUM('N','Y') -- each can have a
value of 'N' or 'Y', and the default value is 'N'.
In the tables_priv and columns_priv tables, the privilege
fields are declared as SET fields:
| Table name | Field name | Possible set elements |
tables_priv | Table_priv | 'Select', 'Insert',
'Update', 'Delete', 'Create', 'Drop', 'Grant', 'References', 'Index', 'Alter'
|
tables_priv | Column_priv | 'Select', 'Insert',
'Update', 'References'
|
columns_priv | Type | 'Select', 'Insert',
'Update', 'References'
|
Briefly, the server uses the grant tables like this:
user table scope fields determine whether to allow or reject
incoming connections. For allowed connections, the privilege fields indicate
the user's global (superuser) privileges.
db and host tables are used together:
db table scope fields determine which users can access which
databases from which hosts. The privilege fields determine which operations
are allowed.
host table is used as an extension of the db table when you
want a given db table entry to apply to several hosts. For example,
if you want a user to be able to use a database from several hosts in
your network, leave the Host value empty in the user's db table
entry, then populate the host table with an entry for each of those
hosts. This mechanism is described more detail in section 6.6 Access control, stage 2: Request verification.
tables_priv and columns_priv tables are similar to
the db table, but are more fine-grained: they apply at the
table and column level rather than at the database level.
Note that administrative privileges (reload, shutdown,
etc.) are specified only in the user table. This is because
administrative operations are operations on the server itself and are not
database-specific, so there is no reason to list such privileges in the
other grant tables. In fact, only the user table need
be consulted to determine whether or not you can perform an administrative
operation.
The file privilege is specified only in the user table, too.
It is not an administrative privilege as such, but your ability to read or
write files on the server host is independent of the database you are
accessing.
The mysqld server reads the contents of the grant tables once, when it
starts up. Changes to the grant tables take effect as indicated in
section 6.7 When privilege changes take effect.
When you modify the contents of the grant tables, it is a good idea to make
sure that your changes set up privileges the way you want. A useful
diagnostic tool is the mysqlaccess script, which Yves Carlier has
provided for the MySQL distribution. Invoke mysqlaccess with
the --help option to find out how it works. Also, see section 6.11 Causes of Access denied errors and section 6.12 How to make MySQL secure against crackers.
Note that mysqlaccess checks access using only the user,
db and host tables. It does not check table- or column-level
privileges.
When you attempt to connect to a MySQL server, the server accepts or rejects the connection based on your identity and whether or not you can verify your identity by supplying the correct password. If not, the server completely denies access to you. Otherwise, the server accepts the connection, then enters stage 2 and waits for requests.
Your identity is based on two pieces of information:
Identity checking is performed using the three user table scope fields
(Host, User and Password). The server accepts the
connection only if a user table entry matches your hostname and user
name, and you supply the correct password.
You can specify user table scope field values as follows:
Host value may be a hostname or an IP number, or 'localhost'
to indicate the local host,
Host
field.
Host value of '%' matches any hostname. A blank Host
value is equivalent to '%'. Note that these values match any
host that can create a connection to your server!
User field, but you can
specify a blank value, which matches any name. If the matching entry for an
incoming connection has a blank user name, the user is considered to be the
anonymous user, the user with no name), rather than the name that the client
actually specified. This means that all further access checking for the
duration of the connection is done using a blank user name.
Password field can be blank. This does not mean that any password
matches, it means the user must connect without specifying a password.
The table below shows some examples of how various combinations of
Host and User values in user table entries apply to
incoming connections:
Host value | User value | Connections matched by entry |
'thomas.loc.gov'
@tab 'fred'
@tab fred, connecting from thomas.loc.gov
| ||
'thomas.loc.gov'
@tab "
@tab Any user, connecting from thomas.loc.gov
| ||
'%'
@tab 'fred'
@tab fred, connecting from any host
| ||
'%'
@tab "
@tab Any user, connecting from any host
| ||
'%.loc.gov'
@tab 'fred'
@tab fred, connecting from any host in the loc.gov domain
| ||
'x.y.%'
@tab 'fred'
@tab fred, connecting from x.y.net, x.y.com,
x.y.edu, etc. (this is probably not useful)
| ||
'144.155.166.177'
@tab 'fred'
@tab fred, connecting from the host with IP address 144.155.166.177
| ||
'144.155.166.%'
@tab 'fred'
@tab fred, connecting from any host in the 144.155.166
class C subnet
|
Since you can use IP wildcard values in the Host field (e.g.,
'144.155.166.%' to match every host on a subnet), there is the
possibility that someone might try to exploit this capability by naming a
host 144.155.166.somewhere.com. To foil such attempts, MySQL
disallows matching on hostnames that start with digits and a dot. Thus, if
you have a host named something like 1.2.foo.com, its name will never
match the Host column of the grant tables. Only an IP number can
match an IP wildcard value.
How does the server choose which user table entry to use if more than
one matches? This question is resolved by the way the user table is
sorted, which is done at server startup time. Suppose the user table
looks like this:
+-----------+----------+- | Host | User | ... +-----------+----------+- | % | root | ... | % | jeffrey | ... | localhost | root | ... | localhost | | ... +-----------+----------+-
When the server reads in the table, it orders the entries with the
most-specific Host values first ('%' in the Host column
means "any host" and is least specific). Entries with the same Host
value are ordered with the most-specific User values first (a blank
User value means "any user" and is least specific). As a result,
the sorted user table looks like this:
+-----------+----------+- | Host | User | ... +-----------+----------+- | localhost | root | ... | localhost | | ... | % | jeffrey | ... | % | root | ... +-----------+----------+-
The matching algorithm looks through the sorted entries and uses the first
match found. For a connection from localhost by jeffrey, the
entries with 'localhost' in the Host column match first. Of
those, the entry with the blank user name matches both the connecting hostname
and user name. (The '%'/'jeffrey' entry would have matched, too, but it
is not the first match in the table.)
Here is another example. Suppose the user table looks like this:
+----------------+----------+- | Host | User | ... +----------------+----------+- | % | jeffrey | ... | thomas.loc.gov | | ... +----------------+----------+-
The sorted table looks like this:
+----------------+----------+- | Host | User | ... +----------------+----------+- | thomas.loc.gov | | ... | % | jeffrey | ... +----------------+----------+-
A connection from thomas.loc.gov by jeffrey is matched by the
first entry, whereas a connection from whitehouse.gov by
jeffrey is matched by the second.
If you have problems connecting to the server, print out the user
table and sort it by hand to see where the first match is being made.
Once you establish a connection, the server enters stage 2. For each request
that comes in on the connection, the server checks whether you have
sufficient privileges for it, based on the type of operation you wish to
perform. This is where the privilege fields in the grant tables come into
play. These privileges can come from any of the user, db,
host, tables_priv or columns_priv tables.
The grant tables are manipulated with GRANT and REVOKE commands.
See section 7.25 GRANT and REVOKE syntax.
(You may find it helpful to refer to the table shown earlier that lists
the fields present in each of the grant tables; see section 6.4 How the privilege system works.)
The user table grants privileges that are assigned to you on a global
basis and that apply no matter what the current database is. For example, if
the user table grants you the delete privilege, you can
delete rows from any database on the server host! In other words,
user table privileges are superuser privileges and it is wise to grant
privileges in the user table only to superusers (such as server or
database administrators). For other users, you should leave the privileges
in the user table set to 'N' and grant privileges on a
database-specific basis only, using the db and host tables.
The db and host tables grant database-specific privileges. The
wildcard characters `%' and `_' can be used in the Host and
Db fields of each table and blank values are allowed in any of the
scope fields. A '%' Host value means "any host." A blank
Host value in the db table means "consult the host
table for further information." A '%' or blank Db value in the
host table means or "any database." A blank User value
matches the anonymous user.
The db and host tables are read in and sorted when the server
starts up (at the same time that it reads the user table). The
db table is sorted on the Host, Db and User scope
fields, and the host table is sorted on the Host and Db
scope fields. As with the user table, sorting puts the most-specific
values first and least-specific values last, and when the server looks for
matching entries, it uses the first match that it finds.
The tables_priv and columns_priv tables grant table- and
column-specific privileges. The same wildcards are allowed in the
Host field as for the Host field in the db and
host tables, but the Db, Table_name and
Column_name fields cannot contain wildcards or be blank.
The tables_priv and columns_priv tables are sorted similarly
to the db table, although since only the Host table may
contain wildcards, the sorting is simpler.
The request verification process is described below. If you are familiar with the access-checking source code, you will notice that the description here differs slightly from the algorithm used in the code. The description is equivalent to what the code actually does; it differs only to make the explanation simpler.
For administrative requests (shutdown, reload, etc.), the
server checks only the user table entry, since that is the only table
that specifies administrative privileges. Access is granted if the entry
allows the requested operation and denied otherwise. For example, if you
want to execute mysqladmin shutdown but your user table entry
doesn't grant the shutdown privilege to you, access is denied
without even checking the db or host tables (there is no need
to do so, because they contain no Shutdown_priv column).
For database-related requests (insert, update, etc.), the
server first checks the user's global (superuser) privileges by looking in
the user table entry. If the entry allows the requested operation,
access is granted.
If the global privileges in the user table are insufficient, the
server determines the user's database-specific privileges by checking the
db and host tables:
db table for a match on the Host,
Db and User fields. Host and User are matched to
the connecting user's hostname and MySQL user name. The Db
field is matched to the database the user wants to access. If there is no
entry for the Host and User, access is denied.
db table entry and its Host field is
not blank, that entry defines the user's database-specific privileges.
db table entry's Host field is blank, it
signifies that the host table enumerates which hosts should be allowed
access to the database. In this case, a further lookup is done in the
host table to find a match on the Host and Db fields.
If no host table entry matches, access is denied. If there is a
match, the user's database-specific privileges are computed as the
intersection of the privileges in the db and host table
entries, i.e., the privileges that are 'Y' in both entries. (This way
you can grant general privileges in the db table entry and then
selectively restrict them on a host-by-host basis using the host table
entries.)
After determining the database-specific privileges granted by the db
and host table entries, the server adds them to the global privileges
granted by the user table. If the result allows the requested
operation, access is granted. Otherwise, the server checks the user's
table and column privileges in the tables_priv and columns_priv
tables and adds those to the user's privileges. Access is allowed or denied
based on the result.
It may not be apparent why the server adds the database-, table- and
column-specific privileges to the global user entry privileges for
those cases in which the user privileges are initially found to be
insufficient for the requested operation. The reason is that a request might
require more than one type of privilege. For example, if you execute an
INSERT ... SELECT statement, you need both insert and
select privileges. Your privileges might be such that the
user table entry grants one privilege and the db table entry
grants the other. In this case, you have the necessary privileges to perform
the request, but the server cannot tell that from either table by itself; the
privileges granted by both entries must be combined.
The host table can be used to maintain a list of "secure" servers.
At TcX, the host table contains a list of all machines on the local
network. These are granted all privileges.
You can also use the host table to indicate hosts that are not
secure. Suppose you have a machine public.your.domain that is located
in a public area that you do not consider secure. You can allow access to
all hosts on your network except that machine with host table entries
like this:
+--------------------+----+- | Host | Db | ... +--------------------+----+- | public.your.domain | % | ... (all privileges set to 'N') | %.your.domain | % | ... (all privileges set to 'Y') +--------------------+----+-
Naturally, you should always test your entries in the grant tables (e.g.,
using mysqlaccess) to make sure your access privileges are actually
set up the way you think they are.
When mysqld starts, all grant table contents are read into memory and
become effective at that point.
Modifications to the grant tables that you perform using GRANT,
REVOKE, or SET PASSWORD 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. Otherwise your changes will have no effect until
you restart the server.
When the server notices that the grant tables have been changed, existing client connections are affected as follows:
USE db_name
command.
After installing MySQL, you set up the initial access privileges by
running scripts/mysql_install_db.
See section 4.7.1 Quick installation overview.
The scripts/mysql_install_db script starts up the mysqld
server, then initializes the grant tables to contain the following set
of privileges:
root user is a superuser and can do anything.
Connections must be made from the local host.
Note:
The initial root password is empty, so anyone can connect as root
without a password and be granted all privileges.
'test' or starting with 'test_'. Any user can
connect from the local host and be treated as the anonymous user.
mysqladmin shutdown or mysqladmin processlist.
Since your installation is initially wide open, one of the first things you
should do is specify a password for the MySQL
root user. You can do this as follows (note that you specify the
password using the PASSWORD() function):
shell> mysql -u root mysql
mysql> UPDATE user SET Password=PASSWORD('new_password')
WHERE user='root';
mysql> FLUSH PRIVILEGES;
or
shell> mysqladmin -u root password new_password
Note that if you use the first method, which updates the password in the
user table directly, you have to tell the server to reread the grant
tables (with FLUSH PRIVILEGES), since the change will go unnoticed
otherwise.
Once the root password has been set, you must supply that password
whenever you connect to the server as root.
You may wish to leave the root password blank so that you don't need
to specify it while you perform additional setup or testing, but be sure to
set it before using your installation for any real production work.
See the scripts/mysql_install_db script to see how it sets up
the default privileges. You can use this as a basis to see how to
add other users.
If you want the initial privileges to be different than those just described
above, you can modify mysql_install_db before you run it.
To recreate the grant tables completely, remove all the `*.ISM' and
`*.ISD' files in the directory containing the mysql database.
(This is the directory named `mysql' under the database directory, which
is listed when you run mysqld --help.) Then run the
mysql_install_db script, possibly after editing it first to have the
privileges you want.
You can add users in two different ways: by using GRANT statements
or by manipulating the MySQL grant tables directly. Use of
GRANT statements is the preferred method.
The examples below show how to use the mysql client to set up new
users. These examples assume that privileges are set up according to the
defaults described in the previous section. This means that to make changes,
you must be on the same machine where mysqld is running, and you must
connect as the MySQL root user, and the root user must
have the insert privilege for the mysql database and the
reload administrative privilege. If you have changed the
root user password, you must also specify it for the mysql
commands below.
You can add new users by issuing GRANT statements:
shell> mysql --user=root mysql
mysql> GRANT ALL PRIVILEGES ON *.* TO monty@localhost
IDENTIFIED BY 'something' WITH GRANT OPTION;
mysql> GRANT ALL PRIVILEGES ON *.* TO monty@"%"
IDENTIFIED BY 'something' WITH GRANT OPTION;
mysql> GRANT RELOAD,PROCESS ON *.* TO admin@localhost;
mysql> GRANT USAGE ON *.* TO dummy@localhost;
These GRANT statements set up three new users:
monty
GRANT statements for
both monty@localhost and monty@"%". If we don't add the
entry with localhost, the anonymous user entry for localhost
that is created by mysql_install_db will take precedence when we
connect from the local host, because it has a more specific Host field
value and comes earlier in the sort order.
admin
localhost without a password and who is
granted the reload and process administrative privileges.
This allows the user to execute the mysqladmin reload,
mysqladmin refresh and mysqladmin flush-* commands, as well as
mysqladmin processlist . No database-related privileges are granted.
They could be granted later by issuing additional GRANT statements.
dummy
'N' because the privilege type is
USAGE, which allows you to set up a user with no privileges. It is
assumed that you would grant database-specific privileges later.
You can also add the same user access information directly by issuing
INSERT statements and then telling the server to reload the grant
tables:
shell> mysql --user=root mysql
mysql> INSERT INTO user VALUES('localhost','monty',PASSWORD('something'),
'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y')
mysql> INSERT INTO user VALUES('%','monty',PASSWORD('something'),
'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y')
mysql> INSERT INTO user SET Host='localhost',User='admin',
Reload_priv='Y', Process_priv='Y';
mysql> INSERT INTO user (Host,User,Password)
VALUES('localhost','dummy',");
mysql> FLUSH PRIVILEGES;
Note that depending on your MySQL version, you may have to use a
different number of 'Y' values above. The extended (more readable)
INSERT syntax that is available starting with 3.22.11 is used here for
the admin user.
Note that to set up a superuser, you need only create a user table
entry with the privilege fields set to 'Y'. No db or
host table entries are necessary.
The privilege columns in the user table were not set explicitly in the
last INSERT statement (for the dummy user), so those columns
are assigned the default value of 'N'.
The following example adds a user custom who can connect from hosts
localhost, server.domain and whitehouse.gov. He wants
to access the bankaccount database only from localhost,
the expenses database only from whitehouse.gov and
the customer database from all three hosts. He wants
to use the password stupid from all three hosts.
To set up this user's privileges using GRANT statements, run these
commands:
shell> mysql --user=root mysql
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
ON bankaccount.*
TO custom@localhost
IDENTIFIED BY 'stupid';
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
ON expenses.*
TO custom@whitehouse.gov
IDENTIFIED BY 'stupid';
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
ON customer.*
TO custom@'%'
IDENTIFIED BY 'stupid';
To set up the user's privileges by modifying the grant tables directly,
run these commands (note the FLUSH PRIVILEGES at the end):
shell> mysql --user=root mysql
mysql> INSERT INTO user (Host,User,Password)
VALUES('localhost','custom',PASSWORD('stupid'));
mysql> INSERT INTO user (Host,User,Password)
VALUES('server.domain','custom',PASSWORD('stupid'));
mysql> INSERT INTO user (Host,User,Password)
VALUES('whitehouse.gov','custom',PASSWORD('stupid'));
mysql> INSERT INTO db
(Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
Create_priv,Drop_priv)
VALUES
('localhost','bankaccount','custom','Y','Y','Y','Y','Y','Y');
mysql> INSERT INTO db
(Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
Create_priv,Drop_priv)
VALUES
('whitehouse.gov','expenses','custom','Y','Y','Y','Y','Y','Y');
mysql> INSERT INTO db
(Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
Create_priv,Drop_priv)
VALUES('%','customer','custom','Y','Y','Y','Y','Y','Y');
mysql> FLUSH PRIVILEGES;
The first three INSERT statements add user table entries that
allow user custom to connect from the various hosts with the given
password, but grant no permissions to him (all privileges are set to the
default value of 'N'). The next three INSERT statements add
db table entries that grant privileges to custom for the
bankaccount, expenses and customer databases, when
accessed from the proper hosts. As usual, when the grant tables are modified
directly, the server must be told to reload the grant tables so that the
changes take effect.
If you want to give a specific user access from any machine in a given
domain, you can issue a GRANT statement like the following:
mysql> GRANT ...
ON *.*
TO myusername@"%.mydomainname.com"
IDENTIFIED BY 'mypassword';
To do the same thing by modifying the grant tables directly, do this:
mysql> INSERT INTO user VALUES ('%.mydomainname.com', 'myusername',
PASSWORD('mypassword'),...);
mysql> FLUSH PRIVILEGES;
You can also use xmysqladmin, mysql_webadmin and even
xmysql to insert, change and update values in the grant tables.
You can find these utilities at http://www.mysql.com/Contrib.
The examples in the preceding sections illustrate an important principle:
when you store a non-empty password using INSERT or UPDATE
statements, you must use the PASSWORD() function to encrypt it. This
is because the user table stores passwords in encrypted form, not as
plaintext. If you forget that fact, you are likely to attempt to set
passwords like this:
shell> mysql -u root mysql
mysql> INSERT INTO user (Host,User,Password)
VALUES('%','jeffrey','bLa81m0');
mysql> FLUSH PRIVILEGES;
The result is that the plaintext value 'bLa81m0' is stored as the
password in the user table. When the user jeffrey attempts to
connect to the server using this password, the mysql client encrypts
it and sends the result to the server. The server compares the value in the
user table (which is the plaintext value 'bLa81m0') to the
encrypted password (which is not 'bLa81m0'). The comparison
fails and the server rejects the connection:
shell> mysql -u jeffrey -pbLa81m0 test Access denied
Since passwords must be encrypted when they are inserted in the user
table, the INSERT statement should have been specified like this
instead:
mysql> INSERT INTO user (Host,User,Password)
VALUES('%','jeffrey',PASSWORD('bLa81m0'));
You must also use the PASSWORD() function when you use SET
PASSWORD statements:
mysql> SET PASSWORD FOR jeffrey@"%" = PASSWORD('bLa81m0');
Note: The PASSWORD() function performs password encryption, but it
does not do so in the same way that Unix passwords are encrypted. You should
not assume that if your Unix password and your MySQL password are
the same, PASSWORD() will result in the same encrypted value as is
stored in the Unix password file.
If you set passwords using the GRANT ... IDENTIFIED BY statement
or the mysqladmin password command, the PASSWORD() function
is unnecessary. They both take care of encrypting the password for you:
mysql> GRANT USAGE ON *.* TO jeffrey@"%" IDENTIFIED BY 'bLa81m0'; shell> mysqladmin -u jeffrey password bLa81m0
Access denied errors
If you encounter Access denied errors when you try to connect to the
MySQL server, the list below indicates some courses of
action you can take to correct the problem:
mysql_install_db script after installing
MySQL, to set up the initial grant table contents? If not, do
so. See section 6.8 Setting up the initial MySQL privileges. Test these initial privileges by
executing this command:
shell> mysql -u root testThe server should let you connect without error. You should also make sure you have a file `user.ISD' in the MySQL database directory (ordinarily, this is `PATH/var/mysql/user.ISD', where
PATH is the
pathname to the MySQL installation root).
shell> mysql -u root mysqlThe server should let you connect because the MySQL
root user
has no password initially. Since that is also a security risk, setting the
root password is something you should do while you're setting up
your other MySQL users.
If you try to connect as root and get this error:
Access denied for user: '@unknown' to database mysqlthis means that you don't have an entry in the
user table with the
User column = root and that mysqld cannot resolve the
hostname for your client. In this case, you must restart the server with the
--skip-grant-tables option and edit your `/etc/hosts' or
`\windows\hosts' file to add a entry for your host.
mysql_fix_privilege_tables script? If not, do so. The structure
of the grant tables changed with MySQL 3.22.11 when the
GRANT statement became functional.
INSERT or
UPDATE statement) and your changes seem to be ignored, remember that
you must issue a FLUSH PRIVILEGES statement or execute a
mysqladmin flush-privileges command to cause the server to reread the
tables. Otherwise your changes have no effect until the next time the server
is restarted. Remember that after you set the root password, you
won't need to specify it until after you flush the privileges, because the
server still won't know you've changed the password yet!
mysqld daemon with the
--skip-grant-tables option. Then you can change the MySQL
grant tables and use the mysqlaccess script to check whether or not
your modifications have the desired effect. When you are satisfied with your
changes, execute mysqladmin flush-privileges to tell the mysqld
server to start using the new grant tables. Note: reloading the
grant tables overrides the --skip-grant-tables option. This allows
you to tell the server to begin using the grant tables again without bringing
it down and restarting it.
mysql -u user_name db_name or mysql
-u user_name -pyour_pass db_name. (Notice that there is no space between
-p and the password; you can also use the --password=your_pass
syntax to specify the password.) If you are able to connect using the
mysql client, there is a problem with your program and not with
the access privileges.
PASSWORD() function if you set the password with the
INSERT, UPDATE or SET PASSWORD statements. The
PASSWORD() function is unnecessary if you specify the password using
the GRANT ... INDENTIFIED BY statement or the mysqladmin
password command.
See section 6.10 How to set up passwords.
localhost is a synonym for your local hostname, and is also the
default host to which clients try to connect if you specify no host
explicitly. However, connections to localhost do not work if you are
running on a system that uses MIT-pthreads (localhost connections are
made using Unix sockets, which are not supported by MIT-pthreads). To avoid
this problem on such systems, you should use the --host option to name
the server host explicitly. This will make a TCP/IP connection to the
mysqld server. In this case, you must have your real hostname in
user table entries on the server host. (This is true even if you are
running a client program on the same host as the server.)
Access denied error when trying to connect to the
database with mysql -u user_name db_name, you may have a problem
with the user table. Check this by executing mysql -u root
mysql and issuing this SQL statement:
mysql> SELECT * FROM user;The result should include an entry with the
Host and User
columns matching your computer's hostname and your MySQL user name.
Access denied error message will tell you who you are trying
to log in as, the host from which you are trying to connect, and whether or not you
were using a password. Normally, you should have one entry in the
user table that exactly matches the hostname and user name that
were given in the error message.
user table
that matches the host from which you are trying to connect:
Host ... is not allowed to connect to this MySQL serverYou can fix this by using the command line tool
mysql (on the server
host!) to add a row to the user table for the user/hostname combination
from which you are trying to connect. If you are not running MySQL
3.22 and you don't know the IP number or hostname of the machine from which
you are connecting, you should put an entry with '%' as the
Host column value in the user table and restart mysqld
with the --log option on the server machine. After trying to connect
from the client machine, the information in the MySQL log will
indicate how you really did connect. (Then replace the '%' in the
user table entry with the actual hostname that shows up in the log.
Otherwise, you'll have a system that is insecure.)
mysql -u root test works but mysql -h your_hostname -u root
test results in Access denied, then you may not have the correct name
for your host in the user table. A common problem here is that the
Host value in the user table entry specifies an unqualified hostname,
but your system's name resolution routines return a fully-qualified domain
name (or vice-versa). For example, if you have an entry with host
'tcx' in the user table, but your DNS tells MySQL that
your hostname is 'tcx.subnet.se', the entry will not work. Try adding
an entry to the user table that contains the IP number of your host as
the Host column value. (Alternatively, you could add an entry to the
user table with a Host value that contains a wildcard--for
example, 'tcx.%'. However, use of hostnames ending with `%' is
insecure and is not recommended!)
mysql -u user_name test works but mysql -u user_name
other_db_name doesn't work, you don't have an entry for other_db_name
listed in the db table.
mysql -u user_name db_name works when executed on the server
machine, but mysql -u host_name -u user_name db_name doesn't work when
executed on another client machine, you don't have the client machine listed
in the user table or the db table.
Access denied, remove from the
user table all entries that have Host values containing
wildcards (entries that contain `%' or `_'). A very common error
is to insert a new entry with Host='%' and
User='some user', thinking that this will allow you to specify
localhost to connect from the same machine. The reason that this
doesn't work is that the default privileges include an entry with
Host='localhost' and User=". Since that entry
has a Host value 'localhost' that is more specific than
'%', it is used in preference to the new entry when connecting from
localhost! The correct procedure is to insert a second entry with
Host='localhost' and User='some_user', or to
remove the entry with with Host='localhost' and
User=".
Access to database deniedyou may have a problem with the
db or host table. If the entry
selected from the db table has an empty value in the Host
column, make sure there are one or more corresponding entries in the
host table specifying to which hosts the db table entry
applies.
Access to database deniedwhen using the SQL commands
SELECT ... INTO OUTFILE or LOAD DATA
INFILE, your entry in the user table probably doesn't have the
file privilege enabled.
mysqld daemon with a debugging
option (for example, --debug=d,general,query). This will print host and
user information about attempted connections, as well as information about
each command issued. See section 19.10 Debugging MySQL.
mysqldump mysql command. As always, post your problem using the
mysqlbug script.
mysqld daemon is
not running or you are trying to connect to the wrong socket or port:
Can't connect to local MySQL server Can't connect to MySQL server on some_hostnameFirst use
ps to see if the mysqld daemon is really running. Check
after this that the socket file exists (normally `/tmp/mysql.sock') or
try to connect to the port with telnet host_name 3306. You can
also try mysqladmin version and mysqladmin -h host_name
version to get some more information. Also, check the error logs in
the MySQL data directory to see if they can provide some hints.
Access denied when you run a client without any options,
make sure you haven't specified an old password in any of your option files!
See section 4.15.4 Option files.
When you connect to a MySQL server, you should normally use passwords. The password is not transmitted in clear text over the connection.
The server/client connection is not encrypted; all information is transferred
in text that can be read by anyone that is able to watch the connection. If
you are concerned about this, you can use the compressed protocol (in
MySQL 3.22 and above) to make things much harder. To make things
even more secure you should install ssh (see
http://www.cs.hut.fi/ssh). With this, you can get an encrypted TCP/IP
connection between a MySQL server and a MySQL client.
To make a MySQL system secure, you should strongly consider the following suggestions:
mysql -u other_user db_name if
other_user has no password. This is common behavior with
client/server applications. You can change the password of all users by
editing the mysql_install_db script before you run it, or only the
password for the MySQL root user like this:
shell> mysql -u root mysql
mysql> UPDATE user SET Password=PASSWORD('new_password')
WHERE user='root';
mysql> FLUSH PRIVILEGES;
root user.
mysqld can be run as any user. You can also create a new Unix user
mysql to make everything even more secure. If you run mysqld
as another Unix user, you don't need to change the root user name in
the user table, because MySQL user names have nothing to do
with Unix user names. You can edit the mysql.server script to start
mysqld as another Unix user. Normally this is done with the su
command. For more details, see section 16.7 How to run MySQL as a normal user.
mysqld runs as is the only Unix user with
read/write privileges in the database directories.
mysqladmin processlist shows the text of the currently executing
queries, so any user who is allowed to execute that command might be able to
see if another user issues an UPDATE user SET
password=PASSWORD('not_secure') query.
mysqld saves an extra connection for users who have the
process privilege, so that a MySQL root user can log
in and check things even if all normal connections are in use.
mysqld daemon! To make this a bit safer, all files generated with
SELECT ... INTO OUTFILE are readable to everyone, and you can't
overwrite existing files.
--secure option to
mysqld should make hostnames safe. In any case, you should be very
careful about using hostname values that contain wildcards!
root user in the mysql.server
script, make sure this script is readable only by root.
The following mysqld options affect security:
--secure
gethostbyname() system call are checked to
make sure they resolve back to the original hostname. This makes it harder
for someone on the outside to get access by simulating another host. This
option also adds some sanity checks of hostnames. The option is turned off
by default in MySQL 3.21 since it sometimes takes a long time to
perform backward resolutions. MySQL 3.22 caches hostnames and has
this option enabled by default.
--skip-grant-tables
mysqladmin
reload.)
--skip-name-resolve
Host column values in the grant
tables must be IP numbers or localhost.
--skip-networking
mysqld must be made
via Unix sockets. This option doesn't work very well on systems that use
MIT-pthreads, because the MIT-pthreads package doesn't support Unix sockets.
Go to the first, previous, next, last section, table of contents.