Table of Contents
This section describes how to set up accounts for clients of your MySQL server. It discusses the following topics:
The meaning of account names and passwords as used in MySQL and how that compares to names and passwords used by your operating system
How to set up new accounts and remove existing accounts
How to change passwords
Guidelines for using passwords securely
See also Account Management Statements, which describes the syntax and use for all user-management SQL statements.
MySQL stores accounts in the user table of the
mysql system database. An account is defined in
terms of a user name and the client host or hosts from which the
user can connect to the server. The account may also have a
password. For information about account representation in the
user table, see Section 4.2, “Grant Tables”.
There are several distinctions between the way user names and passwords are used by MySQL and your operating system:
User names, as used by MySQL for authentication purposes, have
nothing to do with user names (login names) as used by Windows
or Unix. On Unix, most MySQL clients by default try to log in
using the current Unix user name as the MySQL user name, but
that is for convenience only. The default can be overridden
easily, because client programs permit any user name to be
specified with a -u or
--user option. This means that anyone can
attempt to connect to the server using any user name, so you
cannot make a database secure in any way unless all MySQL
accounts have passwords. Anyone who specifies a user name for
an account that has no password is able to connect
successfully to the server.
MySQL user names can be up to 16 characters long. Operating system user names may be of a different maximum length. For example, Unix user names typically are limited to eight characters.
The limit on MySQL user name length is hardcoded in MySQL
servers and clients, and trying to circumvent it by
modifying the definitions of the tables in the
mysql database does not
work.
You should never alter the structure of tables in the
mysql database in any manner whatsoever
except by means of the procedure that is described in
mysql_upgrade — Check and Upgrade MySQL Tables. Attempting to redefine
MySQL's system tables in any other fashion results in
undefined (and unsupported!) behavior. The server is free to
ignore rows that become malformed as a result of such
modifications.
To authenticate client connections that use MySQL built-in
authentication, the server uses MySQL passwords stored in the
user table. These passwords are distinct
from passwords for logging in to your operating system. There
is no necessary connection between the “external”
password you use to log in to a Windows or Unix machine and
the password you use to access the MySQL server on that
machine.
MySQL encrypts passwords stored in the user
table using its own algorithm. This encryption is the same as
that implemented by the
PASSWORD() SQL function but
differs from that used during the Unix login process. Unix
password encryption is the same as that implemented by the
ENCRYPT() SQL function. See the
descriptions of the PASSWORD()
and ENCRYPT() functions in
Encryption and Compression Functions.
From version 4.1 on, MySQL employs a stronger authentication
method that has better password protection during the
connection process than in earlier versions. It is secure even
if TCP/IP packets are sniffed or the mysql
database is captured. (In earlier versions, even though
passwords are stored in encrypted form in the
user table, knowledge of the encrypted
password value could be used to connect to the MySQL server.)
Section 2.2.4, “Password Hashing in MySQL”, discusses password
encryption further.
If the user name and password contain only ASCII characters,
it is possible to connect to the server regardless of
character set settings. To connect when the user name or
password contain non-ASCII characters, the client should call
the mysql_options() C API
function with the MYSQL_SET_CHARSET_NAME
option and appropriate character set name as arguments. This
causes authentication to take place using the specified
character set. Otherwise, authentication will fail unless the
server default character set is the same as the encoding in
the authentication defaults.
Standard MySQL client programs support a
--default-character-set option that causes
mysql_options() to be called
as just described. For programs that use a connector that is
not based on the C API, the connector may provide an
equivalent to mysql_options()
that can be used instead. Check the connector documentation.
The preceding notes do not apply for ucs2,
which is not permitted as a client character set.
The MySQL installation process populates the grant tables with an
initial account or accounts. The names and access privileges for
these accounts are described in
Section 3.4, “Securing the Initial MySQL Accounts”, which also discusses how to
assign passwords to them. Thereafter, you normally set up, modify,
and remove MySQL accounts using statements such as
CREATE USER,
DROP USER,
GRANT, and
REVOKE. See
Account Management Statements.
To connect to a MySQL server with a command-line client, specify user name and password options as necessary for the account that you want to use:
shell> mysql --user=monty --password db_name
If you prefer short options, the command looks like this:
shell> mysql -u monty -p db_name
If you omit the password value following the
--password or -p
option on the command line (as just shown), the client prompts for
one. Alternatively, the password can be specified on the command
line:
shell>mysql --user=monty --password=shell>passworddb_namemysql -u monty -ppassworddb_name
If you use the -p option, there must be
no space between -p and the
following password value.
Specifying a password on the command line should be considered insecure. See Section 2.2.1, “End-User Guidelines for Password Security”. You can use an option file to avoid giving the password on the command line. See Using Option Files.
For additional information about specifying user names, passwords, and other connection parameters, see Connecting to the MySQL Server.
You can create MySQL accounts two ways:
By using account-management statements intended for creating
accounts and establishing their privileges, such as
CREATE USER and
GRANT. These statements cause
the server to make appropriate modifications to the underlying
grant tables.
By manipulating the MySQL grant tables directly with
statements such as INSERT,
UPDATE, or
DELETE.
The preferred method is to use account-management statements because they are more concise and less error-prone than manipulating the grant tables directly. All such statements are described in Account Management Statements. Direct grant table manipulation is discouraged, and is not described here. The server is free to ignore rows that become malformed as a result of such modifications.
Another option for creating accounts is to use the GUI tool
MySQL Workbench. Also, several third-party programs offer capabilities
for MySQL account administration. phpMyAdmin is
one such program.
The following examples show how to use the
mysql client program to set up new accounts.
These examples assume that privileges have been set up according
to the defaults described in Section 3.4, “Securing the Initial MySQL Accounts”.
This means that to make changes, you must connect to the MySQL
server as the MySQL root user, which has the
CREATE USER privilege.
First, use the mysql program to connect to the
server as the MySQL root user:
shell> mysql --user=root mysql
If you have assigned a password to the root
account, you must also supply a --password or
-p option.
After connecting to the server as root, you can
add new accounts. The following example uses
CREATE USER and
GRANT statements to set up four
accounts:
mysql>CREATE USER 'monty'@'localhost' IDENTIFIED BY 'some_pass';mysql>GRANT ALL PRIVILEGES ON *.* TO 'monty'@'localhost'->WITH GRANT OPTION;mysql>CREATE USER 'monty'@'%' IDENTIFIED BY 'some_pass';mysql>GRANT ALL PRIVILEGES ON *.* TO 'monty'@'%'->WITH GRANT OPTION;mysql>CREATE USER 'admin'@'localhost' IDENTIFIED BY 'admin_pass';mysql>GRANT RELOAD,PROCESS ON *.* TO 'admin'@'localhost';mysql>CREATE USER 'dummy'@'localhost';
The accounts created by those statements have the following properties:
Two accounts have a user name of monty and
a password of some_pass. Both are superuser
accounts with full privileges to do anything. The
'monty'@'localhost' account can be used
only when connecting from the local host. The
'monty'@'%' account uses the
'%' wildcard for the host part, so it can
be used to connect from any host.
The 'monty'@'localhost' account is
necessary if there is an anonymous-user account for
localhost. Without the
'monty'@'localhost' account, that
anonymous-user account takes precedence when
monty connects from the local host and
monty is treated as an anonymous user. The
reason for this is that the anonymous-user account has a more
specific Host column value than the
'monty'@'%' account and thus comes earlier
in the user table sort order.
(user table sorting is discussed in
Section 4.4, “Access Control, Stage 1: Connection Verification”.)
The 'admin'@'localhost' account has a
password of admin_pass. This account can be
used only by admin to connect from the
local host. It is granted the
RELOAD and
PROCESS administrative
privileges. These privileges enable the
admin user to execute the
mysqladmin reload, mysqladmin
refresh, and mysqladmin
flush-xxx commands, as
well as mysqladmin processlist . No
privileges are granted for accessing any databases. You could
add such privileges using GRANT
statements.
The 'dummy'@'localhost' account has no
password (which is insecure and not recommended). This account
can be used only to connect from the local host. No privileges
are granted. It is assumed that you will grant specific
privileges to the account using
GRANT statements.
To see the privileges for an account, use
SHOW GRANTS:
mysql> SHOW GRANTS FOR 'admin'@'localhost';
+-----------------------------------------------------+
| Grants for admin@localhost |
+-----------------------------------------------------+
| GRANT RELOAD, PROCESS ON *.* TO 'admin'@'localhost' |
+-----------------------------------------------------+
The next examples create three accounts and grant them access to
specific databases. Each of them has a user name of
custom and password of
obscure:
mysql>CREATE USER 'custom'@'localhost' IDENTIFIED BY 'obscure';mysql>GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP->ON bankaccount.*->TO 'custom'@'localhost';mysql>CREATE USER 'custom'@'host47.example.com' IDENTIFIED BY 'obscure';mysql>GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP->ON expenses.*->TO 'custom'@'host47.example.com';mysql>CREATE USER 'custom'@'%.example.com' IDENTIFIED BY 'obscure';mysql>GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP->ON customer.*->TO 'custom'@'%.example.com';
The three accounts can be used as follows:
The first account can access the
bankaccount database, but only from the
local host.
The second account can access the expenses
database, but only from the host
host47.example.com.
The third account can access the customer
database, from any host in the example.com
domain. This account has access from all machines in the
domain due to use of the “%”
wildcard character in the host part of the account name.
To remove an account, use the DROP
USER statement, which is described in
DROP USER Syntax. For example:
mysql> DROP USER 'jeffrey'@'localhost';
One means of restricting client use of MySQL server resources is
to set the global
max_user_connections system
variable to a nonzero value. This limits the number of
simultaneous connections that can be made by any given account,
but places no limits on what a client can do once connected. In
addition, setting
max_user_connections does not
enable management of individual accounts. Both types of control
are of interest to MySQL administrators.
To address such concerns, MySQL permits limits for individual accounts on use of these server resources:
The number of queries an account can issue per hour
The number of updates an account can issue per hour
The number of times an account can connect to the server per hour
The number of simultaneous connections to the server by an account
Any statement that a client can issue counts against the query limit, unless its results are served from the query cache. Only statements that modify databases or tables count against the update limit.
An “account” in this context corresponds to a row in
the mysql.user table. That is, a connection is
assessed against the User and
Host values in the user
table row that applies to the connection. For example, an account
'usera'@'%.example.com' corresponds to a row in
the user table that has User
and Host values of usera and
%.example.com, to permit
usera to connect from any host in the
example.com domain. In this case, the server
applies resource limits in this row collectively to all
connections by usera from any host in the
example.com domain because all such connections
use the same account.
Before MySQL 5.0.3, an “account” was assessed against
the actual host from which a user connects. This older method of
accounting may be selected by starting the server with the
--old-style-user-limits option. In
this case, if usera connects simultaneously
from host1.example.com and
host2.example.com, the server applies the
account resource limits separately to each connection. If
usera connects again from
host1.example.com, the server applies the
limits for that connection together with the existing connection
from that host.
To establish resource limits for an account, use the
GRANT statement (see
GRANT Syntax). Provide a WITH clause
that names each resource to be limited. The default value for each
limit is zero (no limit). For example, to create a new account
that can access the customer database, but only
in a limited fashion, issue these statements:
mysql>CREATE USER 'francis'@'localhost' IDENTIFIED BY 'frank';mysql>GRANT ALL ON customer.* TO 'francis'@'localhost'->WITH MAX_QUERIES_PER_HOUR 20->MAX_UPDATES_PER_HOUR 10->MAX_CONNECTIONS_PER_HOUR 5->MAX_USER_CONNECTIONS 2;
The limit types need not all be named in the
WITH clause, but those named can be present in
any order. The value for each per-hour limit should be an integer
representing a count per hour. For
MAX_USER_CONNECTIONS, the limit is an integer
representing the maximum number of simultaneous connections by the
account. If this limit is set to zero, the global
max_user_connections system
variable value determines the number of simultaneous connections.
If max_user_connections is also
zero, there is no limit for the account.
To modify limits for an existing account, use a
GRANT USAGE
statement at the global level (ON *.*). The
following statement changes the query limit for
francis to 100:
mysql>GRANT USAGE ON *.* TO 'francis'@'localhost'->WITH MAX_QUERIES_PER_HOUR 100;
The statement modifies only the limit value specified and leaves the account otherwise unchanged.
To remove a limit, set its value to zero. For example, to remove
the limit on how many times per hour francis
can connect, use this statement:
mysql>GRANT USAGE ON *.* TO 'francis'@'localhost'->WITH MAX_CONNECTIONS_PER_HOUR 0;
As mentioned previously, the simultaneous-connection limit for an
account is determined from the
MAX_USER_CONNECTIONS limit and the
max_user_connections system
variable. Suppose that the global
max_user_connections value is 10
and three accounts have individual resource limits specified as
follows:
GRANT ... TO 'user1'@'localhost' WITH MAX_USER_CONNECTIONS 0; GRANT ... TO 'user2'@'localhost' WITH MAX_USER_CONNECTIONS 5; GRANT ... TO 'user3'@'localhost' WITH MAX_USER_CONNECTIONS 20;
user1 has a connection limit of 10 (the global
max_user_connections value)
because it has a MAX_USER_CONNECTIONS limit of
zero. user2 and user3 have
connection limits of 5 and 20, respectively, because they have
nonzero MAX_USER_CONNECTIONS limits.
The server stores resource limits for an account in the
user table row corresponding to the account.
The max_questions,
max_updates, and
max_connections columns store the per-hour
limits, and the max_user_connections column
stores the MAX_USER_CONNECTIONS limit. (See
Section 4.2, “Grant Tables”.) If your user
table does not have these columns, it must be upgraded; see
mysql_upgrade — Check and Upgrade MySQL Tables.
Resource-use counting takes place when any account has a nonzero limit placed on its use of any of the resources.
As the server runs, it counts the number of times each account uses resources. If an account reaches its limit on number of connections within the last hour, the server rejects further connections for the account until that hour is up. Similarly, if the account reaches its limit on the number of queries or updates, the server rejects further queries or updates until the hour is up. In all such cases, the server issues appropriate error messages.
Resource counting occurs per account, not per client. For example, if your account has a query limit of 50, you cannot increase your limit to 100 by making two simultaneous client connections to the server. Queries issued on both connections are counted together.
The current per-hour resource-use counts can be reset globally for all accounts, or individually for a given account:
To reset the current counts to zero for all accounts, issue a
FLUSH
USER_RESOURCES statement. The counts also can be
reset by reloading the grant tables (for example, with a
FLUSH
PRIVILEGES statement or a mysqladmin
reload command).
The counts for an individual account can be reset to zero by setting any of its limits again. Specify a limit value equal to the value currently assigned to the account.
Per-hour counter resets do not affect the
MAX_USER_CONNECTIONS limit.
All counts begin at zero when the server starts. Counts do not carry over through server restarts.
For the MAX_USER_CONNECTIONS limit, an edge
case can occur if the account currently has open the maximum
number of connections permitted to it: A disconnect followed
quickly by a connect can result in an error
(ER_TOO_MANY_USER_CONNECTIONS or
ER_USER_LIMIT_REACHED) if the
server has not fully processed the disconnect by the time the
connect occurs. When the server finishes disconnect processing,
another connection will once more be permitted.
Required credentials for clients that connect to the MySQL server can include a password. This section describes how to assign passwords for MySQL accounts.
MySQL stores passwords in the user table in the
mysql system database. Operations that assign
or modify passwords are permitted only to users with the
CREATE USER privilege, or,
alternatively, privileges for the mysql
database (INSERT privilege to
create new accounts, UPDATE
privilege to modify existing accounts). If the
read_only system variable is
enabled, use of account-modification statements such as
CREATE USER or
SET PASSWORD additionally requires
the SUPER privilege.
The discussion here summarizes syntax only for the most common password-assignment statements. For complete details on other possibilities, see CREATE USER Syntax, GRANT Syntax, and SET PASSWORD Syntax.
MySQL hashes passwords stored in the mysql.user
table to obfuscate them. For most statements described here, MySQL
automatically hashes the password specified. An exception is
SET PASSWORD ... =
PASSWORD(', for
which you use the auth_string')PASSWORD()
function explicitly to hash the password. There are also syntaxes
for CREATE USER,
GRANT, and SET
PASSWORD that permit hashed values to be specified
literally; for details, see the descriptions of those statements.
To assign a password when you create a new account, use
CREATE USER and include an
IDENTIFIED BY clause:
mysql>CREATE USER 'jeffrey'@'localhost'->IDENTIFIED BY 'mypass';
For this CREATE USER syntax, MySQL
automatically hashes the password before storing it in the
mysql.user table.
To assign or change a password for an existing account, use one of the following methods:
Use SET PASSWORD with the
PASSWORD() function:
mysql>SET PASSWORD FOR->'jeffrey'@'localhost' = PASSWORD('mypass');
If you are not connected as an anonymous user, you can change
your own password by omitting the FOR
clause:
mysql> SET PASSWORD = PASSWORD('mypass');
The PASSWORD() function hashes
the password using the hashing method determined by the value
of the old_passwords system
variable value. If SET PASSWORD
rejects the hashed password value returned by
PASSWORD() as not being in the
correct format, it may be necessary to change
old_passwords to change the
hashing method. For descriptions of the permitted values, see
Server System Variables.
You can also use a
GRANT USAGE
statement at the global level (ON *.*) to
assign a password to an account without affecting the
account's current privileges:
mysql>GRANT USAGE ON *.* TO 'jeffrey'@'localhost'->IDENTIFIED BY 'mypass';
For this GRANT syntax, MySQL
automatically hashes the password before storing it in the
mysql.user table.
To change an account password from the command line, use the mysqladmin command:
shell> mysqladmin -u user_name -h host_name password "new_password"
The account for which this command sets the password is the
one with a mysql.user table row that
matches user_name in the
User column and the client host
from which you connect in the
Host column.
For password changes made using mysqladmin,
MySQL automatically hashes the password before storing it in
the mysql.user table.
Applications can use the following guidelines to perform SQL-based auditing that ties database activity to MySQL accounts.
MySQL accounts correspond to rows in the
mysql.user table. When a client connects
successfully, the server authenticates the client to a particular
row in this table. The User and
Host column values in this row uniquely
identify the account and correspond to the
'
format in which account names are written in SQL statements.
user_name'@'host_name'
The account used to authenticate a client determines which
privileges the client has. Normally, the
CURRENT_USER() function can be
invoked to determine which account this is for the client user.
Its value is constructed from the User and
Host columns of the user
table row for the account.
However, there are circumstances under which the
CURRENT_USER() value corresponds
not to the client user but to a different account. This occurs in
contexts when privilege checking is not based the client's
account:
Stored routines (procedures and functions) defined with the
SQL SECURITY DEFINER characteristic
Views defined with the SQL SECURITY DEFINER
characteristic (as of MySQL 5.1.12)
Triggers and events
In those contexts, privilege checking is done against the
DEFINER account and
CURRENT_USER() refers to that
account, not to the account for the client who invoked the stored
routine or view or who caused the trigger to activate. To
determine the invoking user, you can call the
USER() function, which returns a
value indicating the actual user name provided by the client and
the host from which the client connected. However, this value does
not necessarily correspond directly to an account in the
user table, because the
USER() value never contains
wildcards, whereas account values (as returned by
CURRENT_USER()) may contain user
name and host name wildcards.
For example, a blank user name matches any user, so an account of
''@'localhost' enables clients to connect as an
anonymous user from the local host with any user name. In this
case, if a client connects as user1 from the
local host, USER() and
CURRENT_USER() return different
values:
mysql> SELECT USER(), CURRENT_USER();
+-----------------+----------------+
| USER() | CURRENT_USER() |
+-----------------+----------------+
| user1@localhost | @localhost |
+-----------------+----------------+
The host name part of an account can contain wildcards, too. If
the host name contains a '%' or
'_' pattern character or uses netmask notation,
the account can be used for clients connecting from multiple hosts
and the CURRENT_USER() value will
not indicate which one. For example, the account
'user2'@'%.example.com' can be used by
user2 to connect from any host in the
example.com domain. If user2
connects from remote.example.com,
USER() and
CURRENT_USER() return different
values:
mysql> SELECT USER(), CURRENT_USER();
+--------------------------+---------------------+
| USER() | CURRENT_USER() |
+--------------------------+---------------------+
| user2@remote.example.com | user2@%.example.com |
+--------------------------+---------------------+
If an application must invoke
USER() for user auditing (for
example, if it does auditing from within triggers) but must also
be able to associate the USER()
value with an account in the user table, it is
necessary to avoid accounts that contain wildcards in the
User or Host column.
Specifically, do not permit User to be empty
(which creates an anonymous-user account), and do not permit
pattern characters or netmask notation in Host
values. All accounts must have a nonempty User
value and literal Host value.
With respect to the previous examples, the
''@'localhost' and
'user2'@'%.example.com' accounts should be
changed not to use wildcards:
RENAME USER ''@'localhost' TO 'user1'@'localhost'; RENAME USER 'user2'@'%.example.com' TO 'user2'@'remote.example.com';
If user2 must be able to connect from several
hosts in the example.com domain, there should
be a separate account for each host.
To extract the user name or host name part from a
CURRENT_USER() or
USER() value, use the
SUBSTRING_INDEX() function:
mysql>SELECT SUBSTRING_INDEX(CURRENT_USER(),'@',1);+---------------------------------------+ | SUBSTRING_INDEX(CURRENT_USER(),'@',1) | +---------------------------------------+ | user1 | +---------------------------------------+ mysql>SELECT SUBSTRING_INDEX(CURRENT_USER(),'@',-1);+----------------------------------------+ | SUBSTRING_INDEX(CURRENT_USER(),'@',-1) | +----------------------------------------+ | localhost | +----------------------------------------+