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. For information about account
representation in the user table, see
Section 4.2, “Grant Tables”.
The account may also have a password. MySQL supports authentication plugins, so it is possible that an account authenticates using some external authentication method. See Section 5.6, “Pluggable Authentication”.
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 for accounts that use MySQL
native authentication (implemented by the
mysql_native_password authentication
plugin), the server uses 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.
If the server authenticates a client using some other plugin,
the authentication method that the plugin implements may or
may not use a password stored in the user
table. In this case, it is possible that an external password
is also used to authenticate to the MySQL server.
Passwords stored in the user table are
encrypted using plugin-specific algorithms. For information
about MySQL native password hashing, see
Section 2.2.4, “Password Hashing in MySQL”.
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. In addition, character set autodetection is
supported as described in
Connection Character Sets and Collations. 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,
utf16, and utf32, which
are not permitted as client character sets.
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=finley --password db_name
If you prefer short options, the command looks like this:
shell> mysql -u finley -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=finley --password=shell>passworddb_namemysql -u finley -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 'finley'@'localhost' IDENTIFIED BY 'some_pass';mysql>GRANT ALL PRIVILEGES ON *.* TO 'finley'@'localhost'->WITH GRANT OPTION;mysql>CREATE USER 'finley'@'%' IDENTIFIED BY 'some_pass';mysql>GRANT ALL PRIVILEGES ON *.* TO 'finley'@'%'->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 finley and
a password of some_pass. Both are superuser
accounts with full privileges to do anything. The
'finley'@'localhost' account can be used
only when connecting from the local host. The
'finley'@'%' account uses the
'%' wildcard for the host part, so it can
be used to connect from any host.
The 'finley'@'localhost' account is
necessary if there is an anonymous-user account for
localhost. Without the
'finley'@'localhost' account, that
anonymous-user account takes precedence when
finley connects from the local host and
finley 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
'finley'@'%' 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”.)
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.
MySQL uses plugins to perform client authentication; see Section 5.6, “Pluggable Authentication”. The authentication plugin associated with an account determines the algorithm used to hash passwords for that account.
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.
CREATE USER also supports syntax
for specifying the account authentication plugin. See
CREATE USER Syntax.
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. See SET PASSWORD Syntax.
Use a GRANT
USAGE statement at the global level (ON
*.*) to change an account password 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.
When a client connects to the MySQL server, the server uses the
user name provided by the client and the client host to select the
appropriate account row from the mysql.user
table. The server then consults this row to authenticate the
client.
Before MySQL 5.5.7, the server authenticates the password provided
by the client against the Password column of
the account row.
As of MySQL 5.5.7, the server authenticates clients using a
plugin. Selection of the proper account row from the
mysql.user table is based on the user name and
client host, as before, but the server authenticates the client by
determining from the account row which authentication plugin
applies for the client:
If the account row specifies a plugin, the server invokes it to authenticate the user. If the server cannot find the plugin, an error occurs.
If the account row specifies no plugin name, the server
authenticates the account using either the
mysql_native_password or
mysql_old_password plugin, depending on
whether the password hash value in the
Password column used native hashing or the
older pre-4.1 hashing method. Clients must match the password
in the Password column of the account row.
The plugin returns a status to the server indicating whether the user is permitted to connect.
Pluggable authentication enables two important capabilities:
External authentication:
Pluggable authentication makes it possible for clients to
connect to the MySQL server with credentials that are
appropriate for authentication methods other than native
authentication based on passwords stored in the
mysql.user table. For example, plugins can
be created to use external authentication methods such as PAM,
Windows login IDs, LDAP, or Kerberos.
Proxy users: If a user is permitted to connect, an authentication plugin can return to the server a user name different from the name of the connecting user, to indicate that the connecting user is a proxy for another user. While the connection lasts, the proxy user is treated, for purposes of access control, as having the privileges of a different user. In effect, one user impersonates another. For more information, see Section 5.7, “Proxy Users”.
Several authentication plugins are available in MySQL:
Plugins that perform native authentication that matches the
password against the Password column of the
account row. The mysql_native_password
plugin implements authentication based on the native password
hashing method. The mysql_old_password
plugin implements native authentication based on the older
(pre-4.1) password hashing method. See
Section 7.1.1, “The Native Authentication Plugin”, and
Section 7.1.2, “The Old Native Authentication Plugin”. Native
authentication using mysql_native_password
is the default for accounts that have no plugin named
explicitly in their account row.
A plugin that performs external authentication against PAM (Pluggable Authentication Modules), enabling MySQL Server to use PAM to authenticate MySQL users. This plugin supports proxy users as well. See Section 7.1.3, “The PAM Authentication Plugin”.
A plugin that performs external authentication on Windows, enabling MySQL Server to use native Windows services to authenticate client connections. Users who have logged in to Windows can connect from MySQL client programs to the server based on the information in their environment without specifying an additional password. This plugin supports proxy users as well. See Section 7.1.4, “The Windows Native Authentication Plugin”.
A client-side plugin that sends the password to the server without hashing or encryption. This plugin can be used by server-side plugins that require access to the password exactly as provided by the client user. See Section 7.1.5, “The Cleartext Client-Side Authentication Plugin”.
A plugin that authenticates clients that connect from the local host through the Unix socket file. See Section 7.1.6, “The Socket Peer-Credential Authentication Plugin”.
A test plugin that authenticates using MySQL native authentication. This plugin is intended for testing and development purposes, and as an example of how to write an authentication plugin. See Section 7.1.7, “The Test Authentication Plugin”.
For information about current restrictions on the use of pluggable authentication, including which connectors support which plugins, see Restrictions on Pluggable Authentication.
Third-party connector developers should read that section to determine the extent to which a connector can take advantage of pluggable authentication capabilities and what steps to take to become more compliant.
If you are interested in writing your own authentication plugins, see Writing Authentication Plugins.
This section provides general instructions for installing and using authentication plugins.
In general, pluggable authentication uses corresponding plugins on the server and client sides, so you use a given authentication method like this:
On the server host, install the library containing the appropriate server plugin, if necessary, so that the server can use it to authenticate client connections. Similarly, on each client host, install the library containing the appropriate client plugin for use by client programs.
Create MySQL accounts that specify use of the plugin for authentication.
When a client connects, the server plugin tells the client program which client plugin to use for authentication.
The instructions here use an example authentication plugin included in MySQL distributions (see Section 7.1.7, “The Test Authentication Plugin”). The procedure is similar for other authentication plugins; substitute the appropriate plugin and file names.
The example authentication plugin has these characteristics:
The server-side plugin name is
test_plugin_server.
The client-side plugin name is
auth_test_plugin.
Both plugins are located in the shared library file named
auth_test_plugin.so in the plugin
directory (the directory named by the
plugin_dir system variable).
The file name suffix might differ on your system.
Install and use the example authentication plugin as follows:
Make sure that the plugin library is installed on the server and client hosts.
Install the server-side test plugin at server startup or at runtime:
To install the plugin at startup, use the
--plugin-load option. With
this plugin-loading method, the option must be given each
time you start the server. For example, use these lines in
a my.cnf option file:
[mysqld] plugin-load=test_plugin_server=auth_test_plugin.so
To install the plugin at runtime, use the
INSTALL PLUGIN statement:
INSTALL PLUGIN test_plugin_server SONAME 'auth_test_plugin.so';
This installs the plugin permanently and need be done only once.
Verify that the plugin is installed. For example, use
SHOW PLUGINS:
mysql> SHOW PLUGINS\G
...
*************************** 21. row ***************************
Name: test_plugin_server
Status: ACTIVE
Type: AUTHENTICATION
Library: auth_test_plugin.so
License: GPL
For other ways to check the plugin, see Obtaining Server Plugin Information.
To specify that a MySQL user must be authenticated using a
specific server plugin, name the plugin in the
IDENTIFIED WITH clause of the
CREATE USER statement that
creates the user:
CREATE USER 'testuser'@'localhost' IDENTIFIED WITH test_plugin_server;
Connect to the server using a client program. The test plugin
authenticates the same way as native MySQL authentication, so
provide the usual --user and
--password options that you
normally use to connect to the server. For example:
shell> mysql --user=your_name --password=your_pass
For connections by testuser, the server
sees that the account must be authenticated using the
server-side plugin named test_plugin_server
and communicates to the client program which client-side
plugin it must use—in this case,
auth_test_plugin.
In the case that the account uses the authentication method
that is the default for both the server and the client
program, the server need not communicate to the client which
plugin to use, and a round trip in client/server negotiation
can be avoided. This is true for accounts that use native
MySQL authentication
(mysql_native_password).
The
--default-auth=
option can be specified on the mysql
command line as a hint about which client-side plugin the
program can expect to use, although the server will override
this if the user account requires a different plugin.
plugin_name
If the client program does not find the plugin, specify a
--plugin-dir=
option to indicate where the plugin is located.
dir_name
If you start the server with the
--skip-grant-tables option,
authentication plugins are not used even if loaded because the
server performs no client authentication and permits any client
to connect. Because this is insecure, you might want to use
--skip-grant-tables in
conjunction with
--skip-networking to prevent
remote clients from connecting.
Authentication to the MySQL server occurs by means of authentication plugins. The plugin that authenticates a given connection may request that the connecting (external) user be treated as a different user for privilege-checking purposes. This enables the external user to be a proxy for the second user; that is, to have the privileges of the second user:
The external user is a “proxy user” (a user who can impersonate or become known as another user).
The second user is a “proxied user” (a user whose identity can be taken on by a proxy user).
This section describes how the proxy user capability works. For general information about authentication plugins, see Section 5.6, “Pluggable Authentication”. For information about specific plugins, see Section 7.1, “Authentication Plugins”. For information about writing authentication plugins that support proxy users, see Implementing Proxy User Support in Authentication Plugins.
For proxying to occur for a given authentication plugin, these conditions must be satisfied:
A proxy user account must be set up to be authenticated by the
plugin. Use the CREATE USER or
GRANT statement to associate an
account with a plugin.
For a client connecting to the proxy account to be treated as a proxy user, the plugin must return a user name different from the client user name, to indicate the user name for the proxied account.
The proxy user account must have the
PROXY privilege for the proxied
account. Use the GRANT
statement for this.
The proxy mechanism permits mapping only the client user name to the proxied user name. There is no provision for mapping host names. When a connecting client matches a proxy account, the server attempts to find a match for a proxied account using the user name returned by the authentication plugin and the host name of the proxy account.
Consider the following definitions:
-- create proxy user CREATE USER 'employee_ext'@'localhost' IDENTIFIED WITH my_auth_plugin AS 'my_auth_string'; -- create proxied user CREATE USER 'employee'@'localhost' IDENTIFIED BY 'employee_pass'; -- grant PROXY privilege for proxy user to proxied user GRANT PROXY ON 'employee'@'localhost' TO 'employee_ext'@'localhost';
When a client connects as employee_ext from the
local host, MySQL uses my_auth_plugin to
perform authentication. Suppose that
my_auth_plugin returns a user name of
employee to the server, based on the content of
'my_auth_string' and perhaps by consulting some
external authentication system. The name
employee differs from
employee_ext, so returning
employee serves as a request to the server to
treat the employee_ext client, for purposes of
privilege checking, as the employee local user.
In this case, employee_ext is the proxy user
and employee is the proxied user.
The server verifies that proxy authentication for
employee is possible for the
employee_ext user by checking whether
employee_ext (the proxy user) has the
PROXY privilege for
employee (the proxied user). If this privilege
has not been granted, an error occurs.
When proxying occurs, the USER() and
CURRENT_USER() functions can be used to see the
difference between the connecting user (the proxy user) and the
account whose privileges apply during the current session (the
proxied user). For the example just described, those functions
return these values:
mysql> SELECT USER(), CURRENT_USER();
+------------------------+--------------------+
| USER() | CURRENT_USER() |
+------------------------+--------------------+
| employee_ext@localhost | employee@localhost |
+------------------------+--------------------+
In the CREATE USER statement that
creates the proxy user account, the IDENTIFIED
WITH clause that names the authentication plugin is
optionally followed by an AS
' clause
specifying a string that the server passes to the plugin when the
user connects. If present, the string provides information that
helps the plugin determine how to map the external client user
name to a proxied user name. It is up to each plugin whether it
requires the auth_string'AS clause. If so, the format of
the authentication string depends on how the plugin intends to use
it. Consult the documentation for a given plugin for information
about the authentication string values it accepts.
The PROXY privilege is needed to
enable an external user to connect as and have the privileges of
another user. To grant this privilege, use the
GRANT statement. For example:
GRANT PROXY ON 'proxied_user' TO 'proxy_user';
The statement creates a row in the
mysql.proxies_priv grant table.
At connection time, proxy_user must
represent a valid externally authenticated MySQL user, and
proxied_user must represent a valid
locally authenticated user. Otherwise, the connection attempt
fails.
The corresponding REVOKE syntax
is:
REVOKE PROXY ON 'proxied_user' FROM 'proxy_user';
MySQL GRANT and
REVOKE syntax extensions work as
usual. For example:
GRANT PROXY ON 'a' TO 'b', 'c', 'd'; GRANT PROXY ON 'a' TO 'd' IDENTIFIED BY ...; GRANT PROXY ON 'a' TO 'd' WITH GRANT OPTION; GRANT PROXY ON 'a' TO ''@''; REVOKE PROXY ON 'a' FROM 'b', 'c', 'd';
In the preceding example, ''@'' is the
default proxy user and means “any user.” Default
proxy user are discussed in
Default Proxy Users.
The PROXY privilege can be
granted in these cases:
By a user that has GRANT PROXY ... WITH GRANT
OPTION for
proxied_user.
By proxied_user for itself: The
value of USER() must exactly match
CURRENT_USER() and
proxied_user, for both the user
name and host name parts of the account name.
The initial root account created during MySQL
installation has the
PROXY ... WITH GRANT
OPTION privilege for ''@'', that
is, for all users and all hosts. This enables
root to set up proxy users, as well as to
delegate to other accounts the authority to set up proxy users.
For example, root can do this:
CREATE USER 'admin'@'localhost' IDENTIFIED BY 'test'; GRANT PROXY ON ''@'' TO 'admin'@'localhost' WITH GRANT OPTION;
Those statements create an admin user that
can manage all GRANT PROXY mappings. For
example, admin can do this:
GRANT PROXY ON sally TO joe;
To specify that some or all users should connect using a given
authentication plugin, create a “blank” MySQL user,
associate it with that plugin for authentication, and let the
plugin return the real authenticated user name (if different
from the blank user). For example, suppose that there exists a
plugin named ldap_auth that implements LDAP
authentication and maps connecting users onto either a developer
or manager account. To set up proxying of users onto these
accounts, use the following statements:
-- create default proxy user CREATE USER ''@'' IDENTIFIED WITH ldap_auth AS 'O=Oracle, OU=MySQL'; -- create proxied users CREATE USER 'developer'@'localhost' IDENTIFIED BY 'developer_pass'; CREATE USER 'manager'@'localhost' IDENTIFIED BY 'manager_pass'; -- grant PROXY privilege for default proxy user to proxied users GRANT PROXY ON 'manager'@'localhost' TO ''@''; GRANT PROXY ON 'developer'@'localhost' TO ''@'';
Now assume that a client tries to connect as follows:
mysql --user=myuser --password='myuser_pass' ...
The server will not find myuser defined as a
MySQL user. But because there is a blank user account
(''@''), that matches the client user name
and host name, the server authenticates the client against that
account: The server invokes the ldap_auth
authentication plugin and passes myuser and
myuser_pass to it as the user name and
password.
If the ldap_auth plugin finds in the LDAP
directory that myuser_pass is not the correct
password for myuser, authentication fails and
the server rejects the connection.
If the password is correct and ldap_auth
finds that myuser is a developer, it returns
the user name developer to the MySQL server,
rather than myuser. Returning a user name
different from the client user name of myuser
signals to the server that it should treat
myuser as a proxy. The server verifies that
''@'' can authenticate as
developer (because it has the
PROXY privilege to do so) and
accepts the connection. The session proceeds with
myuser having the privileges of
developer, the proxied user. (These
privileges should be set up by the DBA using
GRANT statements, not shown.) The
USER() and
CURRENT_USER() functions return
these values:
mysql> SELECT USER(), CURRENT_USER();
+------------------+---------------------+
| USER() | CURRENT_USER() |
+------------------+---------------------+
| myuser@localhost | developer@localhost |
+------------------+---------------------+
If the plugin instead finds in the LDAP directory that
myuser is a manager, it returns
manager as the user name and the session
proceeds with myuser having the privileges of
manager.
mysql> SELECT USER(), CURRENT_USER();
+------------------+-------------------+
| USER() | CURRENT_USER() |
+------------------+-------------------+
| myuser@localhost | manager@localhost |
+------------------+-------------------+
For simplicity, external authentication cannot be multilevel:
Neither the credentials for developer nor
those for manager are taken into account in
the preceding example. However, they are still used if a client
tries to connect and authenticate directly as the
developer or manager
account, which is why those accounts should be assigned
passwords.
If you intend to create a default proxy user, check for other existing “match any user” accounts that take precedence over the default proxy user and thus prevent that user from working as intended.
In the preceding discussion, the default proxy user account has
'' in the host part, which matches any host.
If you set up a default proxy user, take care to also check
whether nonproxy accounts exist with the same user part and
'%' in the host part, because
'%' also matches any host, but has precedence
over '' by the rules that the server uses to
sort account rows internally (see
Section 4.4, “Access Control, Stage 1: Connection Verification”).
Suppose that a MySQL installation includes these two accounts:
-- create default proxy user CREATE USER ''@'' IDENTIFIED WITH some_plugin AS 'some_auth_string'; -- create anonymous user CREATE USER ''@'%' IDENTIFIED BY 'some_password';
The first account (''@'') is intended as the
default proxy user, used to authenticate connections for users
who do not otherwise match a more-specific account. The second
account (''@'%') is an anonymous-user
account, which might have been created, for example, to enable
users without their own account to connect anonymously.
Both accounts have the same user part (''),
which matches any user. And each account has a host part that
matches any host. Nevertheless, there is a priority in account
matching for connection attempts because the matching rules sort
a host of '%' ahead of ''.
For accounts that do not match any more-specific account, the
server attempts to authenticate them against
''@'%' (the anonymous user) rather than
''@'' (the default proxy user). The result is
that the default proxy account is never used.
To avoid this problem, use one of the following strategies:
Remove the anonymous account so that it does not conflict with the default proxy user. This might be a good idea anyway if you want to associate every connection with a named user.
Use a more-specific default proxy user that matches ahead of
the anonymous user. For example, to permit only
localhost proxy connections, use
''@'localhost':
CREATE USER ''@'localhost' IDENTIFIED WITH some_plugin AS 'some_auth_string';
In addition, modify any GRANT PROXY
statements to name ''@'localhost' rather
than ''@'' as the proxy user.
Be aware that this strategy prevents anonymous-user
connections from localhost.
Create multiple proxy users, one for local connections and one for “everything else” (remote connections). This can be useful particularly when local users should have different privileges from remote users.
Create the proxy users:
-- create proxy user for local connections CREATE USER ''@'localhost' IDENTIFIED WITH some_plugin AS 'some_auth_string'; -- create proxy user for remote connections CREATE USER ''@'%' IDENTIFIED WITH some_plugin AS 'some_auth_string';
Create the proxied users:
-- create proxied user for local connections CREATE USER 'developer'@'localhost' IDENTIFIED BY 'some_password'; -- create proxied user for remote connections CREATE USER 'developer'@'%' IDENTIFIED BY 'some_password';
Grant the proxy privilege to each proxy user for the corresponding proxied user:
GRANT PROXY ON 'developer'@'localhost' TO ''@'localhost'; GRANT PROXY ON 'developer'@'%' TO ''@'%';
Finally, grant appropriate privileges to the local and remote proxied users (not shown).
Assume that the
some_plugin/'some_auth_string'
combination causes some_plugin to map the
client user name to developer. Local
connections match the ''@'localhost'
proxy user, which maps to the
'developer'@'localhost' proxied user.
Remote connections match the ''@'%' proxy
user, which maps to the 'developer'@'%'
proxied user.
Two system variables help trace the proxy login process:
proxy_user: This value is
NULL if proxying is not used. Otherwise,
it indicates the proxy user account. For example, if a
client authenticates through the ''@''
proxy account, this variable is set as follows:
mysql> SELECT @@proxy_user;
+--------------+
| @@proxy_user |
+--------------+
| ''@'' |
+--------------+
external_user: Sometimes
the authentication plugin may use an external user to
authenticate to the MySQL server. For example, when using
Windows native authentication, a plugin that authenticates
using the windows API does not need the login ID passed to
it. However, it still uses a Windows user ID to
authenticate. The plugin may return this external user ID
(or the first 512 UTF-8 bytes of it) to the server using the
external_user read-only session variable.
If the plugin does not set this variable, its value is
NULL.
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
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 | +----------------------------------------+