mysqld Command-line Options
In most cases you should manage mysqld options through option files.
See section 4.1.2 `my.cnf' Option Files.
mysqld and mysqld.server read options from the
mysqld and server groups. mysqld_safe read options
from the mysqld, server, mysqld_safe and
safe_mysqld groups. An embedded MySQL server usually reads
options from the server, embedded and
xxxxx_SERVER, where xxxxx is the name of the application.
mysqld accepts a lot of command-line options. Here follows some
of the most common ones. For a full list execute mysqld --help.
Options used for replication are listed in a separate section, see
section 4.10.6 Replication Options in `my.cnf'.
--ansi
-b, --basedir=path
--big-tables
--bind-address=IP
--console
--log-error
is specified. On Windows, mysqld will not close the console screen if
this option is used.
--character-sets-dir=path
--chroot=path
mysqld daemon in chroot environment at startup. Recommended
security measure since MySQL 4.0 (MySQL 3.23 is not able to provide
100% closed chroot jail).
It somewhat limits LOAD DATA INFILE and
SELECT ... INTO OUTFILE though.
--core-file
mysqld dies. For some systems you must also
specify --core-file-size to mysqld_safe.
See section 4.7.2 mysqld_safe, The Wrapper Around mysqld.
Note that on some systems, like Solaris, you will
not get a core file if you are also using the --user option.
-h, --datadir=path
--debug[...]=
--with-debug, you can use this
option to get a trace file of what mysqld is doing.
See section E.1.2 Creating Trace Files.
--default-character-set=charset
--default-table-type=type
--delay-key-write[= OFF | ON | ALL]
DELAYED KEYS should be used. See section 5.5.2 Tuning Server Parameters.
--delay-key-write-for-all-tables; In MySQL 4.0.3 you should use --delay-key-write=ALL instead.
MyISAM table.
See section 5.5.2 Tuning Server Parameters.
--des-key-file=filename
DES_ENCRYPT() and DES_DECRYPT()
from this file.
--enable-external-locking (was --enable-locking)
lockd does not fully work (as on Linux), you will easily get
mysqld to deadlock.
--enable-named-pipe
-T, --exit-info
--flush
-?, --help
--init-file=file
-L, --language=...
-l, --log[=file]
--log-bin=[file]
--log-bin-index[=file]
--log-error[=file]
--log-isam[=file]
--log-slow-queries[=file]
long_query_time seconds to
execute to file. See section 4.9.5 The Slow Query Log.
--log-update[=file]
file.# where # is a unique number if not
given. See section 4.9.3 The Update Log. The update log is deprecated and will be
removed in MySQL 5.0; you should use the binary log instead
(--log-bin). See section 4.9.4 The Binary Log. Starting from version 5.0,
using --log-update will just turn on the binlog instead.
--log-long-format
--log-slow-queries then queries that are not using indexes are logged
to the slow query log.
--low-priority-updates
INSERT/DELETE/UPDATE)
will have lower priority than selects. It can also be done via
{INSERT | REPLACE | UPDATE | DELETE} LOW_PRIORITY ... to lower
the priority of only one query, or by
SET LOW_PRIORITY_UPDATES=1 to change the priority in one
thread. See section 5.3.2 Table Locking Issues.
--memlock
mysqld process in memory. This works only if your
system supports the mlockall() system call (like Solaris). This
may help if you have a problem where the operating system is causing
mysqld to swap on disk.
--myisam-recover [=option[,option...]]]
DEFAULT, BACKUP, FORCE or QUICK. You can
also set this explicitly to "" if you want to disable this
option. If this option is used, mysqld will on open check if the
table is marked as crashed or if the table wasn't closed properly.
(The last option only works if you are running with
--skip-external-locking.) If this is the case mysqld will run
check on the table. If the table was corrupted, mysqld will
attempt to repair it.
The following options affects how the repair works.
| Option | Description |
| DEFAULT | The same as not giving any option to
--myisam-recover.
|
| BACKUP | If the data table was changed during recover, save a backup of the `table_name.MYD' datafile as `table_name-datetime.BAK'. |
| FORCE | Run recover even if we will lose more than one row from the .MYD file. |
| QUICK | Don't check the rows in the table if there aren't any delete blocks. |
BACKUP,FORCE. This will force a repair of a table even if some rows
would be deleted, but it will keep the old datafile as a backup so that
you can later examine what happened.
--new
--new option can be used to make the server
behave as 4.1 in certain aspects, easing a 4.0 to 4.1 upgrade:
TIMESTAMP is returned as a string with the format
'YYYY-MM-DD HH:MM:SS'.
See section 6.2 Column Types.
--pid-file=path
mysqld_safe.
-P, --port=...
-o, --old-protocol
--one-thread
-O, --set-variable var=option
--help lists variables. You can find a full
description for all variables in the SHOW VARIABLES section in this
manual. See section 4.5.7.4 SHOW VARIABLES. The tuning server parameters section includes
information of how to optimise these. Please note that --set-variable
is deprecated since MySQL 4.0, just use --var=option on its own.
See section 5.5.2 Tuning Server Parameters.
In MySQL 4.0.2 one can set a variable directly with
--variable-name=option and set-variable is no longer needed
in option files.
If you want to restrict the maximum value a startup option can be set to
with SET, you can define this by using the
--maximum-variable-name command line option. See section 5.5.6 SET Syntax.
Note that when setting a variable to a value, MySQL may automatically
correct it to stay within a given range and also adjusts the value a
little to fix for the used algorithm.
--safe-mode
--safe-show-database
SHOW DATABASES command returns only those
databases for which the user has some kind of privilege.
From version 4.0.2 this option is deprecated and doesn't do anything
(the option is enabled by default) as we now have the
SHOW DATABASES privilege. See section 4.3.1 GRANT and REVOKE Syntax.
--safe-user-create
INSERT privilege to the
mysql.user table or any column in this table.
--skip-bdb
--skip-concurrent-insert
MyISAM
tables. (This is only to be used if you think you have found a bug in this
feature.)
--skip-delay-key-write; In MySQL 4.0.3 you should use --delay-key-write=OFF instead.
DELAY_KEY_WRITE option for all tables.
See section 5.5.2 Tuning Server Parameters.
--skip-grant-tables
mysqladmin
flush-privileges or mysqladmin reload.)
--skip-host-cache
--skip-innodb
--skip-external-locking (was --skip-locking)
isamchk or myisamchk you must
shut down the server. See section 1.2.3 How Stable Is MySQL?. Note that in MySQL Version
3.23 you can use REPAIR and CHECK to repair/check MyISAM
tables.
--skip-name-resolve
Host column values in the grant tables
must be IP numbers or localhost. See section 5.5.5 How MySQL uses DNS.
--skip-networking
mysqld must be made via Unix sockets. This option is highly
recommended for systems where only local requests are allowed. See section 5.5.5 How MySQL uses DNS.
--skip-new
--skip-symlink
--symbolic-links || --skip-symbolic-links
CREATE TABLE .... INDEX/DATA DIRECTORY="path-to-dir" command.
When you delete or rename a table, the file that the symbolic link points
to will also be deleted/renamed.
On Windows, this means that you can create a directory.sym file that
contains the path to the real directory. See section 2.6.2.5 Splitting Data Across Different Disks on Windows.
--skip-safemalloc
--with-debug=full, all programs
will check the memory for overruns for every memory allocation and memory
freeing. As this checking is very slow, you can avoid this, when you don't
need memory checking, by using this option.
--skip-show-database
SHOW DATABASES command, unless the user has the
SHOW DATABASES privilege. From version 4.0.2 you should no longer
need this option, since access can now be granted specifically with the
SHOW DATABASES privilege.
--skip-stack-trace
mysqld under a debugger. On some systems you also have to use
this option to get a core file. See section E.1 Debugging a MySQL server.
--skip-thread-priority
--socket=path
/tmp/mysql.sock.
--sql-mode=option[,option[,option...]]
REAL_AS_FLOAT,
PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE,
SERIALIZE, ONLY_FULL_GROUP_BY. It can also be empty
("") if you want to reset this.
By specifying all of the above options is same as using --ansi.
With this option one can turn on only needed SQL modes. See section 1.8.2 Running MySQL in ANSI Mode.
--temp-pool
--transaction-isolation= { READ-UNCOMMITTED | READ-COMMITTED | REPEATABLE-READ | SERIALIZABLE }
SET TRANSACTION Syntax.
-t, --tmpdir=path
/tmp
directory resides on a partition too small to hold temporary tables.
Starting from MySQL 4.1, this option accepts several paths separated
by colon : (semicolon ; on Windows). They will be used
in round-robin fashion.
-u, --user= [user_name | userid]
mysqld daemon as user user_name or userid (numeric).
This option is mandatory when starting mysqld as root.
Starting from MySQL 3.23.56 and 4.0.12:
To avoid a possible security hole where a user adds an --user=root
option to some `my.cnf' file, mysqld will only use the first
--user option specified and give a warning if there are multiple
options. Note that `/etc/my.cnf' and `datadir/my.cnf' may override
a command line option - therefore it is recommended to put this option in
`/etc/my.cnf'.
-V, --version
-W, --log-warnings (Was --warnings)
Aborted connection... to the
`.err' file. Enabling it is recommended if you use replication
for example (you will get more messages about what is happening,
like network failures and reconnections). See section A.2.10 Communication Errors / Aborted Connection.
One can change most values for a running server with the
SET command. See section 5.5.6 SET Syntax.
MySQL can, since Version 3.22, read default startup options for the server and for clients from option files.
MySQL reads default options from the following files on Unix:
| Filename | Purpose |
/etc/my.cnf | Global options |
DATADIR/my.cnf | Server-specific options |
defaults-extra-file | The file specified with --defaults-extra-file=# |
~/.my.cnf | User-specific options |
DATADIR is the MySQL data directory (typically
`/usr/local/mysql/data' for a binary installation or
`/usr/local/var' for a source installation). Note that this is the
directory that was specified at configuration time, not the one specified
with --datadir when mysqld starts up! (--datadir has no
effect on where the server looks for option files, because it looks for them
before it processes any command-line arguments.)
MySQL reads default options from the following files on Windows:
| Filename | Purpose |
windows-directory\my.ini | Global options |
C:\my.cnf | Global options |
Note that on Windows, you should specify all paths with / instead of
\. If you use \, you need to specify this twice, as
\ is the escape character in MySQL.
MySQL tries to read option files in the order listed above. If multiple option files exist, an option specified in a file read later takes precedence over the same option specified in a file read earlier. Options specified on the command-line take precedence over options specified in any option file. Some options can be specified using environment variables. Options specified on the command-line or in option files take precedence over environment variable values. See section F Environment Variables.
The following programs support option files: mysql,
mysqladmin, mysqld, mysqld_safe, mysql.server,
mysqldump, mysqlimport, mysqlshow, mysqlcheck,
myisamchk, and myisampack.
Any long option that may be given on the command-line when running a MySQL
program can be given in an option file as well (without the leading double
dash). Run the program with --help to get a list of available options.
An option file can contain lines of the following forms:
#comment
[group]
group is the name of the program or group for which you want to set
options. After a group line, any option or set-variable lines
apply to the named group until the end of the option file or another group
line is given.
option
--option on the command-line.
option=value
--option=value on the command-line.
set-variable = variable=value
--set-variable variable=value on the command-line.
This syntax must be used to set a mysqld variable.
Please note that --set-variable is deprecated since MySQL 4.0,
just use --variable=value on its own.
The client group allows you to specify options that apply to all
MySQL clients (not mysqld). This is the perfect group to use
to specify the password you use to connect to the server. (But make
sure the option file is readable and writable only by yourself.)
Note that for options and values, all leading and trailing blanks are automatically deleted. You may use the escape sequences `\b', `\t', `\n', `\r', `\\', and `\s' in your value string (`\s' == blank).
Here is a typical global option file:
[client] port=3306 socket=/tmp/mysql.sock [mysqld] port=3306 socket=/tmp/mysql.sock set-variable = key_buffer_size=16M set-variable = max_allowed_packet=1M [mysqldump] quick
Here is typical user option file:
[client] # The following password will be sent to all standard MySQL clients password=my_password [mysql] no-auto-rehash set-variable = connect_timeout=2 [mysqlhotcopy] interactive-timeout
If you have a source distribution, you will find sample configuration
files named `my-xxxx.cnf' in the `support-files' directory.
If you have a binary distribution, look in the `DIR/support-files'
directory, where DIR is the pathname to the MySQL
installation directory (typically `/usr/local/mysql'). Currently
there are sample configuration files for small, medium, large, and very
large systems. You can copy `my-xxxx.cnf' to your home directory
(rename the copy to `.my.cnf') to experiment with this.
All MySQL clients that support option files support the following options:
| Option | Description |
| --no-defaults | Don't read any option files. |
| --print-defaults | Print the program name and all options that it will get. |
| --defaults-file=full-path-to-default-file | Only use the given configuration file. |
| --defaults-extra-file=full-path-to-default-file | Read this configuration file after the global configuration file but before the user configuration file. |
Note that the above options must be first on the command-line to work!
--print-defaults may however be used directly after the
--defaults-xxx-file commands.
Note for developers: Option file handling is implemented simply by processing all matching options (that is, options in the appropriate group) before any command-line arguments. This works nicely for programs that use the last instance of an option that is specified multiple times. If you have an old program that handles multiply-specified options this way but doesn't read option files, you need add only two lines to give it that capability. Check the source code of any of the standard MySQL clients to see how to do this.
In shell scripts you can use the `my_print_defaults' command to parse the config files:
shell> my_print_defaults client mysql --port=3306 --socket=/tmp/mysql.sock --no-auto-rehash
The above output contains all options for the groups 'client' and 'mysql'.
In some cases you may want to have many different mysqld daemons
(servers) running on the same machine. You may for example want to run
a new version of MySQL for testing together with an old version
that is in production. Another case is when you want to give different
users access to different mysqld servers that they manage themselves.
One way to get a new server running is by starting it with a different socket and port as follows:
shell> MYSQL_UNIX_PORT=/tmp/mysqld-new.sock shell> MYSQL_TCP_PORT=3307 shell> export MYSQL_UNIX_PORT MYSQL_TCP_PORT shell> scripts/mysql_install_db shell> bin/mysqld_safe &
The environment variables appendix includes a list of other environment
variables you can use to affect mysqld. See section F Environment Variables.
The above is the quick and dirty way that one commonly uses for testing. The nice thing with this is that all connections you do in the above shell will automatically be directed to the new running server!
If you need to do this more permanently, you should create an option file for each server. See section 4.1.2 `my.cnf' Option Files. In your startup script that is executed at boot time you should specify this command for both servers, with an appropriate path for each command:
mysqld_safe --defaults-file=path-to-option-file
At least the following options should be different per server:
The following options should be different, if they are used:
If you want more performance, you can also specify the following differently:
See section 4.1.1 mysqld Command-line Options.
Starting from MySQL 4.1, tmpdir can be set to a list of paths
separated by colon : (semicolon ; on Windows). They
will be used in round-robin fashion. This feature can be used to
spread load between several physical disks.
If you are installing binary MySQL versions (.tar files) and
start them with ./bin/mysqld_safe then in most cases the only
option you need to add/change is the socket and port
argument to mysqld_safe.
See section 4.1.4 Running Multiple MySQL Servers on the Same Machine.
There are circumstances when you might want to run multiple servers on the same machine. For example, you might want to test a new MySQL release while leaving your existing production setup undisturbed. Or you might be an Internet service provider that wants to provide independent MySQL installations for different customers.
If you want to run multiple servers, the easiest way is to compile the servers
with different TCP/IP ports and socket files so they are not
both listening to the same TCP/IP port or socket file. See section 4.7.3 mysqld_multi, A Program for Managing Multiple MySQL Servers.
Assume an existing server is configured for the default port number and
socket file. Then configure the new server with a configure command
something like this:
shell> ./configure --with-tcp-port=port_number \
--with-unix-socket-path=file_name \
--prefix=/usr/local/mysql-3.22.9
Here port_number and file_name should be different from the
default port number and socket file pathname, and the --prefix value
should specify an installation directory different from the one under which
the existing MySQL installation is located.
You can check the socket used by any currently executing MySQL server with this command:
shell> mysqladmin -h hostname --port=port_number variables
Note that if you specify ``localhost'' as a hostname, mysqladmin
will default to using Unix sockets instead of TCP/IP.
In MySQL 4.1 you can also specify the protocol to use by using the
--protocol=(TCP | SOCKET | PIPE | MEMORY) option.
If you have a MySQL server running on the port you used, you will get a list of some of the most important configurable variables in MySQL, including the socket name.
You don't have to recompile a new MySQL server just to start with
a different port and socket. You can change the port and socket to be used
by specifying them at runtime as options to mysqld_safe:
shell> /path/to/mysqld_safe --socket=file_name --port=port_number
mysqld_multi can also take mysqld_safe (or mysqld)
as an argument and pass the options from a configuration file to
mysqld_safe and further to mysqld.
If you run the new server on the same database directory as another
server with logging enabled, you should also specify the name of the log
files to mysqld_safe with --log, --log-update,
--log-bin or --log-slow-queries. Otherwise, both
servers may be trying to write to the same log file.
Warning: normally you should never have two servers that update data in the same database! If your OS doesn't support fault-free system locking, this may lead to unpleasant surprises!
If you want to use another database directory for the second server, you
can use the --datadir=path option to mysqld_safe.
Note also that starting several MySQL servers
(mysqlds) in different machines and letting them access one data
directory over NFS is generally a bad idea! The problem
is that the NFS will become the bottleneck with the speed. It is
not meant for such use. And last but not least, you would still have to
come up with a solution how to make sure that two or more mysqlds
are not interfering with each other. At the moment there is no platform
that would 100% reliable do the file locking (lockd daemon
usually) in every situation. Yet there would be one more possible risk
with NFS; it would make the work even more complicated for
lockd daemon to handle. So make it easy for your self and forget
about the idea. The working solution is to have one computer with an
operating system that efficiently handles threads and have several CPUs
in it.
When you want to connect to a MySQL server that is running with a different port than the port that is compiled into your client, you can use one of the following methods:
--host 'hostname' --port=port_number to connect
with TCP/IP, or [--host localhost] --socket=file_name to connect via
a Unix socket.
--protocol=tcp to connect with TCP/IP and
--protocol=socket to connect via a Unix socket.
DBD::mysql module you can read the options
from the MySQL option files. See section 4.1.2 `my.cnf' Option Files.
$dsn = "DBI:mysql:test;mysql_read_default_group=client;
mysql_read_default_file=/usr/local/mysql/data/my.cnf"
$dbh = DBI->connect($dsn, $user, $password);
MYSQL_UNIX_PORT and MYSQL_TCP_PORT environment variables
to point to the Unix socket and TCP/IP port before you start your clients.
If you normally use a specific socket or port, you should place commands
to set these environment variables in your `.login' file.
See section F Environment Variables.
MySQL has an advanced but non-standard security/privilege system. This section describes how it works.
Anyone using MySQL on a computer connected to the Internet should read this section to avoid the most common security mistakes.
In discussing security, we emphasise the necessity of fully protecting the entire server host (not simply the MySQL server) against all types of applicable attacks: eavesdropping, altering, playback, and denial of service. We do not cover all aspects of availability and fault tolerance here.
MySQL uses security based on Access Control Lists (ACLs) for all connections, queries, and other operations that a user may attempt to perform. There is also some support for SSL-encrypted connections between MySQL clients and servers. Many of the concepts discussed here are not specific to MySQL at all; the same general ideas apply to almost all applications.
When running MySQL, follow these guidelines whenever possible:
root user) access to the
user table in the mysql database! This is critical.
The encrypted password is the real password in MySQL.
Anyone who knows the password which is listed in the user table
and has access to the host listed for the account can easily log
in as that user.
GRANT and
REVOKE commands are used for controlling access to MySQL. Do
not grant any more privileges than necessary. Never grant privileges to all
hosts.
Checklist:
mysql -u root. If you are able to connect successfully to the
server without being asked for a password, you have problems. Anyone
can connect to your MySQL server as the MySQL
root user with full privileges!
Review the MySQL installation instructions, paying particular
attention to the item about setting a root password.
SHOW GRANTS and check to see who has access to
what. Remove those privileges that are not necessary using the REVOKE
command.
MD5(), SHA1() or
another one-way hashing function.
nmap. MySQL uses port 3306 by default. This port should
be inaccessible from untrusted hosts. Another simple way to check whether
or not your MySQL port is open is to try the following command
from some remote machine, where server_host is the hostname of
your MySQL server:
shell> telnet server_host 3306If you get a connection and some garbage characters, the port is open, and should be closed on your firewall or router, unless you really have a good reason to keep it open. If
telnet just hangs or the
connection is refused, everything is OK; the port is blocked.
; DROP
DATABASE mysql;''. This is an extreme example, but large security leaks
and data loss may occur as a result of hackers using similar techniques,
if you do not prepare for them.
Also remember to check numeric data. A common mistake is to protect only
strings. Sometimes people think that if a database contains only publicly
available data that it need not be protected. This is incorrect. At least
denial-of-service type attacks can be performed on such
databases. The simplest way to protect from this type of attack is to use
apostrophes around the numeric constants: SELECT * FROM table
WHERE ID='234' rather than SELECT * FROM table WHERE ID=234.
MySQL automatically converts this string to a number and
strips all non-numeric symbols from it.
Checklist:
%22 (`"'), %23
(`#'), and %27 (`'') in the URL.
addslashes() function.
As of PHP 4.0.3, a mysql_escape_string() function is available
that is based on the function of the same name in the MySQL C API.
mysql_real_escape_string() API call.
escape and quote modifiers for query streams.
quote() method or use placeholders.
PreparedStatement object and placeholders.
tcpdump and strings utilities. For most cases,
you can check whether MySQL data streams are unencrypted
by issuing a command like the following:
shell> tcpdump -l -i eth0 -w - src or dst port 3306 | strings(This works under Linux and should work with small modifications under other systems.) Warning: If you do not see data this doesn't always actually mean that it is encrypted. If you need high security, you should consult with a security expert.
When you connect to a MySQL server, you normally should use a password. The password is not transmitted in clear text over the connection, however the encryption algorithm is not very strong, and with some effort a clever attacker can crack the password if he is able to sniff the traffic between the client and the server. If the connection between the client and the server goes through an untrusted network, you should use an SSH tunnel to encrypt the communication.
All other information is transferred as text that can be read by anyone
who is able to watch the connection. If you are concerned about this,
you can use the compressed protocol (in MySQL Version 3.22 and above)
to make things much harder. To make things even more secure you should use
ssh. You can find an Open Source ssh client at
http://www.openssh.org/, and a commercial ssh client at
http://www.ssh.com/. With this, you can get an encrypted TCP/IP
connection between a MySQL server and a MySQL client.
If you are using MySQL 4.0, you can also use internal OpenSSL support. See section 4.3.9 Using Secure Connections.
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. It is common behaviour with client/server
applications that the client may specify any user name. 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. This is
very dangerous, because any user with the FILE privilege will be able
to create files as root (for example, ~root/.bashrc). To
prevent this, mysqld will refuse to run as root unless it
is specified directly using a --user=root option.
mysqld can be run as an ordinary unprivileged user instead.
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. To start mysqld as another Unix user, add a user
line that specifies the user name to the [mysqld] group of the
`/etc/my.cnf' option file or the `my.cnf' option file in the
server's data directory. For example:
[mysqld] user=mysqlThis will cause the server to start as the designated user whether you start it manually or by using
mysqld_safe or mysql.server.
For more details, see section A.3.2 How to Run MySQL As a Normal User.
--skip-symlink option). This is especially important if you run
mysqld as root as anyone that has write access to the mysqld data
directories could then delete any file in the system!
See section 5.6.1.2 Using Symbolic Links for Tables.
mysqld runs as is the only user with
read/write privileges in the database directories.
PROCESS privilege to all users. The output of
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 reserves 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.
FILE privilege to all users. Any user that has this
privilege can write a file anywhere in the filesystem with the privileges of
the mysqld daemon! To make this a bit safer, all files generated with
SELECT ... INTO OUTFILE are writeable by everyone, and you cannot
overwrite existing files.
The FILE privilege may also be used to read any world readable
file that is accessible to the Unix user that the server runs as. One can also
read any file to the current database (which the user need some privilege for).
This could be abused, for example, by using LOAD DATA to load
`/etc/passwd' into a table, which can then be read with
SELECT.
max_user_connections variable in
mysqld.
mysqld Concerning Security
The following mysqld options affect security:
--local-infile[=(0|1)]
--local-infile=0 then one can't use LOAD DATA LOCAL
INFILE.
--safe-show-database
SHOW DATABASES command returns only those
databases for which the user has some kind of privilege.
From version 4.0.2 this option is deprecated and doesn't do anything
(the option is enabled by default) as we now have the
SHOW DATABASES privilege. See section 4.3.1 GRANT and REVOKE Syntax.
--safe-user-create
GRANT
command, if the user doesn't have the INSERT privilege for the
mysql.user table. If you want to give a user access to just create
new users with those privileges that the user has right to grant, you should
give the user the following privilege:
mysql> GRANT INSERT(user) ON mysql.user TO 'user'@'hostname';This will ensure that the user can't change any privilege columns directly, but has to use the
GRANT command to give privileges to other users.
--skip-grant-tables
mysqladmin
flush-privileges or 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 is unsuitable when using a MySQL version prior to 3.23.27 with
the MIT-pthreads package, because Unix sockets were not supported by
MIT-pthreads at that time.
--skip-show-database
SHOW DATABASES command, unless the user has the
SHOW DATABASES privilege. From version 4.0.2 you should no longer
need this option, since access can now be granted specifically with the
SHOW DATABASES privilege.
LOAD DATA LOCAL
In MySQL 3.23.49 and MySQL 4.0.2, we added some new options to deal with
possible security issues when it comes to LOAD DATA LOCAL.
There are two possible problems with supporting this command:
As the reading of the file is initiated from the server, one could theoretically create a patched MySQL server that could read any file on the client machine that the current user has read access to, when the client issues a query against the table.
In a web environment where the clients are connecting from a web
server, a user could use LOAD DATA LOCAL to read any files
that the web server process has read access to (assuming a user could
run any command against the SQL server).
There are two separate fixes for this:
If you don't configure MySQL with --enable-local-infile, then
LOAD DATA LOCAL will be disabled by all clients, unless one
calls mysql_options(... MYSQL_OPT_LOCAL_INFILE, 0) in the client.
See section 9.1.3.39 mysql_options().
For the mysql command-line client, LOAD DATA LOCAL can be
enabled by specifying the option --local-infile[=1], or disabled
with --local-infile=0.
By default, all MySQL clients and libraries are compiled with
--enable-local-infile, to be compatible with MySQL 3.23.48 and
before.
One can disable all LOAD DATA LOCAL commands in the MySQL server
by starting mysqld with --local-infile=0.
In the case that LOAD DATA LOCAL INFILE is disabled in the server or
the client, you will get the error message (1148):
The used command is not allowed with this MySQL version
The primary function of the MySQL privilege system is to
authenticate a user connecting from a given host, and to associate that user
with privileges on a database such as
SELECT, INSERT, UPDATE and DELETE.
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.
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
joe who connects from office.com need not be the same
person as the user joe who connects from elsewhere.com.
MySQL handles this by allowing you to distinguish users on different
hosts that happen to have the same name: you can grant joe one set
of privileges for connections from office.com, and a different set
of privileges for connections from elsewhere.com.
MySQL access control involves two stages:
SELECT
privilege for the table or the DROP privilege for the database.
Note that if your privileges are changed (either by yourself or someone else) while you are connected, those changes will not necessarily take effect with your next query or queries. See section 4.3.3 When Privilege Changes Take Effect for details.
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 here:
| 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
| |
References_priv | |||
Reload_priv | |||
Shutdown_priv | |||
Process_priv | |||
File_priv | |||
Show_db_priv | |||
Super_priv | |||
Create_tmp_table_priv | Create_tmp_table_priv | Create_tmp_table_priv
| |
Lock_tables_priv | Lock_tables_priv | Lock_tables_priv
| |
Execute_priv | |||
Repl_slave_priv | |||
Repl_client_priv | |||
ssl_type | |||
ssl_cypher | |||
x509_issuer | |||
x509_cubject | |||
max_questions | |||
max_updates | |||
max_connections |
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 here:
| Table name | tables_priv | columns_priv |
| Scope fields | Host | Host
|
Db | Db
| |
User | User
| |
Table_name | Table_name
| |
Column_name
| ||
| Privilege fields | Table_priv | Column_priv
|
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, that is, 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 Version
3.22.12 or later.
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 4.2.10 Access Control, Stage 2: Request Verification.
Scope fields are strings, declared as shown here; the default value for each is the empty string:
| Field name | Type | Notes |
Host | CHAR(60) | |
User | CHAR(16) | |
Password | CHAR(16) | |
Db | CHAR(64) | (CHAR(60) for the
tables_priv and columns_priv tables)
|
Table_name | CHAR(60) | |
Column_name | CHAR(60) |
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
| Column_priv
| '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, any privileges granted in
the user table indicate the user's global (superuser) privileges.
These privileges apply to all databases on the server.
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 4.2.10 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 levels 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 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 4.3.3 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. For help in
diagnosing problems, see section 4.2.13 Causes of Access denied Errors. For advice on security issues,
see section 4.2.2 How to Make MySQL Secure Against Crackers.
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.
Note that mysqlaccess checks access using only the user,
db and host tables. It does not check table- or column-level
privileges.
Information about user privileges 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 4.3.3 When Privilege Changes Take Effect.
The names used in this manual to refer to the privileges provided by MySQL version 4.0.2 are shown here, 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 |
ALTER | Alter_priv | tables |
DELETE | Delete_priv | tables |
INDEX | Index_priv | tables |
INSERT | Insert_priv | tables |
SELECT | Select_priv | tables |
UPDATE | Update_priv | tables |
CREATE | Create_priv | databases, tables, or indexes |
DROP | Drop_priv | databases or tables |
GRANT | Grant_priv | databases or tables |
REFERENCES | References_priv | databases or tables |
CREATE TEMPORARY TABLES | Create_tmp_table_priv | server administration |
EXECUTE | Execute_priv | server administration |
FILE | File_priv | file access on server |
LOCK TABLES | Lock_tables_priv | server administration |
PROCESS | Process_priv | server administration |
RELOAD | Reload_priv | server administration |
REPLICATION CLIENT | Repl_client_priv | server administration |
REPLICATION SLAVE | Repl_slave_priv | server administration |
SHOW DATABASES | Show_db_priv | server administration |
SHUTDOWN | Shutdown_priv | server administration |
SUPER | Super_priv | server administration |
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
any world readable file accessable by the MySQL server and create a new
world readable file in any directory where the MySQL server can write.
The user can also read any file in the current database directory.
The user can however not change any existing file.
The remaining privileges are used for administrative operations, which are
performed using the mysqladmin program. The table here 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, and flush-tables
|
SHUTDOWN | shutdown
|
PROCESS | processlist
|
SUPER | kill
|
The reload command tells the server to re-read 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 and SUPER privilege to
kill threads initiated by other users. See section 4.5.6 KILL Syntax.
It is a good idea in general to grant privileges only to those users who need them, but you should exercise particular caution in granting certain privileges:
GRANT privilege allows users to give away their privileges to
other users. Two users with different privileges and with the GRANT
privilege are able to combine privileges.
ALTER privilege may be used to subvert the privilege system
by renaming tables.
FILE privilege can be abused to read any world-readable file
on the server or any file in the current database directory on the
server into a database table, the contents of which can then be accessed
using SELECT.
SHUTDOWN privilege can be abused to deny service to other
users entirely, by terminating the server.
PROCESS privilege can be used to view the plain text of
currently executing queries, including queries that set or change passwords.
mysql database can be used to change passwords
and other access privilege information. (Passwords are stored
encrypted, so a malicious user cannot simply read them to know the plain
text password.) If they can access the mysql.user password
column, they can use it to log into the MySQL server
for the given user. (With sufficient privileges, the same user can
replace a password with a different one.)
There are some things that you cannot do with the MySQL privilege system:
MySQL client programs generally require that you specify connection
parameters when you want to access a MySQL server: 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]
Alternate forms of the -h, -u, and -p options are
--host=host_name, --user=user_name, and
--password=your_pass. Note that there is no space between
-p or --password= and the password following it.
Note: Specifying a password on the command-line is not secure!
Any user on your system may then find out your password by typing a command
like: ps auxww. See section 4.1.2 `my.cnf' Option Files.
mysql uses default values for connection parameters that are missing
from the command-line:
localhost.
-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. This can be done in a couple of ways:
[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.1.2 `my.cnf' Option Files.
mysql using MYSQL_HOST. The
MySQL user name can be specified using USER (this is for
Windows only). The password can be specified using MYSQL_PWD
(but this is insecure; see the next section). See section F Environment Variables.
When you attempt to connect to a MySQL server, the server accepts or rejects the connection based on your identity and whether you can verify your identity by supplying the correct password. If not, the server denies access to you completely. 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.
Values in the user table scope fields may be specified 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.
Host value means that the privilege should be anded
with the entry in the host table that matches the given host name.
You can find more information about this in the next chapter.
Host values specified as
IP numbers, you can specify a netmask indicating how many address bits to
use for the network number. For example:
mysql> GRANT ALL PRIVILEGES ON db.*
-> TO david@'192.58.197.0/255.255.255.0';
This will allow everyone to connect from an IP where the following is true:
user_ip & netmask = host_ip.In the above example all IP:s in the interval 192.58.197.0 - 192.58.197.255 can connect to the MySQL server.
User field, but you can
specify a blank value, which matches any name. If the user table
entry that matches 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 a blank user name
is used for all further access checking for the duration of the connection
(that is, during Stage 2).
Password field can be blank. This does not mean that any password
matches, it means the user must connect without specifying a password.
Non-blank Password values represent encrypted passwords.
MySQL does not store passwords in plaintext form for anyone to
see. Rather, the password supplied by a user who is attempting to
connect is encrypted (using the PASSWORD() function). The
encrypted password is then used when the client/server is checking if
the password is correct. (This is done without the encrypted password
ever traveling over the connection.) Note that from MySQL's
point of view the encrypted password is the REAL password, so you should
not give anyone access to it! In particular, don't give normal users
read access to the tables in the mysql database!
From version 4.1, MySQL employs a different password and login mechanism
that is secure even if TCP/IP packets are sniffed and/or the mysql database
is captured.
The examples here show 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' | 'fred' | fred, connecting from thomas.loc.gov
|
'thomas.loc.gov' | '' | Any user, connecting from thomas.loc.gov
|
'%' | 'fred' | fred, connecting from any host
|
'%' | '' | Any user, connecting from any host |
'%.loc.gov' | 'fred' | fred, connecting from any host in the loc.gov domain
|
'x.y.%' | 'fred' | fred, connecting from x.y.net, x.y.com,x.y.edu, etc. (this is probably not useful)
|
'144.155.166.177' | 'fred' | fred, connecting from the host with IP address 144.155.166.177
|
'144.155.166.%' | 'fred' | fred, connecting from any host in the 144.155.166 class C subnet
|
'144.155.166.0/255.255.255.0' | 'fred' | Same as previous example |
Because you can use IP wildcard values in the Host field (for example,
'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.
An incoming connection may be matched by more than one entry in the
user table. For example, a connection from thomas.loc.gov by
fred would be matched by several of the entries just shown above. How
does the server choose which entry to use if more than one matches? The
server resolves this question by sorting the user table after reading
it at startup time, then looking through the entries in sorted order when a
user attempts to connect. The first matching entry is the one that is used.
user table sorting works as follows. 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). The resulting
sorted user table looks like this:
+-----------+----------+- | Host | User | ... +-----------+----------+- | localhost | root | ... | localhost | | ... | % | jeffrey | ... | % | root | ... +-----------+----------+-
When a connection is attempted, the server 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.
A common misconception is to think that for a given user name, all entries
that explicitly name that user will be used first when the server attempts to
find a match for the connection. This is simply not true. The previous
example illustrates this, where a connection from thomas.loc.gov by
jeffrey is first matched not by the entry containing 'jeffrey'
as the User field value, but by the entry with no user name!
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.
If connection was successful, but your privileges are not what you
expected you may use CURRENT_USER() function (new in version
4.0.6) to see what user/host combination your connection actually
matched. See section 6.3.6.2 Miscellaneous Functions.
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 to perform 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 4.3.1 GRANT and REVOKE Syntax. (You may find it helpful to refer to
section 4.2.6 How the Privilege System Works, which lists the fields present in each of the grant
tables.)
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. 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.
Values in the scope fields may be specified as follows:
Host
and Db fields of either table. If you wish to use for instance a
`_' character as part of a database name, specify it as `\_' in
the GRANT command.
'%' Host value in the db table means ``any host.'' A
blank Host value in the db table means ``consult the
host table for further information.''
'%' or blank Host value in the host table means ``any
host.''
'%' or blank Db value in either table means ``any database.''
User value in either table 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. Values in the scope fields may be specified as
follows:
Host field of either table.
'%' or blank Host value in either table means ``any host.''
Db, Table_name and Column_name fields cannot contain
wildcards or be blank in either table.
The tables_priv and columns_priv tables are sorted on
the Host, Db, and User fields. This is similar to
db table sorting, although the sorting is simpler because
only the Host field may contain wildcards.
The request verification process is described here. (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, because 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. (They
contain no Shutdown_priv column, so there is no need to do so.)
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. The Host and User fields 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 (not the union!) of the privileges in the db and
host table entries, that is, 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.
Expressed in boolean terms, the preceding description of how a user's privileges are calculated may be summarised like this:
global privileges OR (database privileges AND host privileges) OR table privileges OR column privileges
It may not be apparent why, if the global user entry privileges are
initially found to be insufficient for the requested operation, the server
adds those privileges to the database-, table-, and column-specific privileges
later. 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 the entries
in both tables 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 by using 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 (for
example, using mysqlaccess) to make sure your access privileges are
actually set up the way you think they are.
MySQL user accounts are listed in the user table of the mysql
database. Each MySQL account is assigned a password, although
what is stored in the Password column of the user table is not the
plaintext version of the password, but a hash value computed from
it. Password hash values are computed by the PASSWORD() function.
MySQL uses passwords in two phases of client/server communication:
In other words, the server uses hash values during authentication when
a client first attempts to connect. The server generates hash values
if a connected client invokes the PASSWORD() function or uses a
GRANT
or SET PASSWORD statement to set or change a password.
The password hashing mechanism was updated in MySQL 4.1 to provide
better security and to reduce the risk of passwords being stolen.
However, this new mechanism is understood only by the 4.1 server and
4.1 clients, which can result in some compatibility problems.
A 4.1 client can connect to a pre-4.1 server, because the client
understands both the old and new password hashing mechanisms. However,
a pre-4.1 client that attempts to connect to a 4.1 server may run into
difficulties. For example, a 4.0 mysql client that attempts to connect
to a 4.1 server may fail with the following error message:
shell> mysql Client does not support authentication protocol requested by server; consider upgrading MySQL client
The following discussion describes the differences between the old and new password mechanisms, and what you should do if you upgrade your server to 4.1 but need to maintain backward compatibility with pre-4.1 clients.
Note: This discussion contrasts 4.1 behaviour with pre-4.1 behaviour, but the 4.1 behaviour described here actually begins with 4.1.1. MySQL 4.1.0 is an ``odd'' release because it has a slightly different mechanism than that implemented in 4.1.1 and up. Differences between 4.1.0 and more recent versions are described later.
Prior to MySQL 4.1, password hashes computed by the PASSWORD() function
are 16 bytes long. Such hashes look like this:
mysql> SELECT PASSWORD('mypass');
+--------------------+
| PASSWORD('mypass') |
+--------------------+
| 6f8c114b58f2ce9e |
+--------------------+
The Password column of the user table (in which these hashes are stored)
also is 16 bytes long before MySQL 4.1.
As of MySQL 4.1, the PASSWORD() function has been modified to produce
a longer 41-byte hash value:
mysql> SELECT PASSWORD('mypass');
+-----------------------------------------------+
| PASSWORD('mypass') |
+-----------------------------------------------+
| *43c8aa34cdc98eddd3de1fe9a9c2c2a9f92bb2098d75 |
+-----------------------------------------------+
Accordingly, the Password column in the user table also must be 41
bytes long to store these values:
Password column
will be made 41 bytes long automatically.
mysql_fix_privilege_tables script to update the length of the
Password
column from 16 to 41 bytes. (The script does not change existing
password values, which remain 16 bytes long.)
A widened Password column can store password hashes in both the old and
new formats. The format of any given password hash value can be
determined two ways:
The longer password hash format has better cryptographic properties, and client authentication based on long hashes is more secure than that based on the older short hashes.
The differences between short and long password hashes are relevant both for how the server uses passwords during authentication and for how it generates password hashes for connected clients that perform password-changing operations.
The way in which the server uses password hashes during authentication is affected by the width of the Password column:
For short-hash accounts, the authentication process is actually a bit more secure for 4.1 clients than for older clients. In terms of security, the gradient from least to most secure is:
The way in which the server generates password hashes for connected
clients is affected by the width of the Password column and by the
--old-passwords option. A 4.1 server generates long hashes only if certain
conditions are met:
The Password column must be wide enough to hold long
values and the --old-passwords option must not be given.
These conditions apply as follows:
Password column must be wide enough to hold long hashes (41 bytes).
If the column has not been updated and still has the pre-4.1 width
(16 bytes), the server notices that long hashes cannot fit into it and
generates only short hashes when a client performs password-changing
operations using PASSWORD(), GRANT, or SET PASSWORD.
(This behaviour
occurs if you have upgraded to 4.1 but have not run the
mysql_fix_privilege_tables script to widen the Password column.)
Password column is wide, it can store either short or long
password hashes. In this case, PASSWORD(), GRANT, and SET PASSWORD
will generate long hashes unless the server was started with the
--old-passwords option. This option forces the server to generate
short passsword hashes instead.
The purpose of the --old-passwords option is to allow you to maintain
backward compatibility with pre-4.1 clients under circumstances where
the server would otherwise generate long password hashes. It doesn't
affect authentication (4.1 clients can still use accounts that have
long password hashes), but it does prevent creation of a long
password hash in the user table as the result of a password-changing
operation. Were that to occur, the account no longer could be used
by pre-4.1 clients. Without the --old-passwords option, the following
scenario is possible:
--old-passwords,
this results in the account having a long password hash.
This scenario illustrates that it is dangerous to run a 4.1 server
without using the --old-passwords option if you must support older pre-4.1
clients. By running the server with --old-passwords, password-changing
operations will not generate long password hashes and thus do not cause
accounts to become inaccessible to older clients. (Those clients cannot
inadvertently lock themselves out by changing their password and ending
up with a long password hash.)
The downside of the --old-passwords option is that any passwords you
create or change will use short hashes, even for 4.1 clients. Thus, you
lose the additional security provided by long password hashes. If you want
to create an account that has a long hash (for example, for use by 4.1
clients), you must do so while running the server without
--old-passwords.
The following scenarios are possible for running a 4.1 server:
Scenario 1) Narrow Password column in user table
Password column.
PASSWORD(), GRANT, or SET PASSWORD use short hashes
exclusively. Any change to an account's password results in
that account having a short password hash.
--old-passwords option can be used but is superfluous because
with a narrow Password column, the server will be generating short
password hashes anyway.
Scenario 2) Long Password column; server not started with
--old-passwords option
Password column.
PASSWORD(), GRANT, or SET PASSWORD use long hashes
exclusively. Any change to an account's password results in that
account having a long password hash.
OLD_PASSWORD() may be used to explicitly generate a short hash. For
example, to assign an account a short password, use UPDATE as follows:
mysql> UPDATE user SET Password = OLD_PASSWORD('mypass')
-> WHERE Host = 'some_host' AND User = 'some_user';
mysql> FLUSH PRIVILEGES;
As indicated earlier, a danger in this scenario is that it is
possible for accounts that have a short password hash to become
inaccessible to pre-4.1 clients. Any change to such an account's
password made via GRANT, SET PASSWORD, or PASSWORD() results in
the account being given a long password hash, and from that point
on, no pre-4.1 client can authenticate to that account until the
client upgrades to 4.1.
Scenario 3) Long Password column; server started with
--old-passwords option
Password column.
--old-passwords).
PASSWORD(), GRANT, or SET PASSWORD use short hashes
exclusively. Any change to an account's password results in that
account having a short password hash.
In this scenario, you cannot create accounts that have long password
hashes, because --old-passwords prevents generation of long hashes. Also,
if you create an account with a long hash before using the
--old-passwords
option, changing the account's password while --old-passwords is in
effect results in the account being given a short password, causing it
to lose the security benefits of a longer hash.
The disadvantages for these scenarios may be summarized as follows:
Scenario 1) You cannot take advantage of longer hashes that provide more secure authentication.
Scenario 2) Accounts with short hashes become inaccessible to pre-4.1
clients if you change their passwords without explicitly using
OLD_PASSWORD().
Scenario 3) --old-passwords prevents accounts with short hashes from
becoming inaccessible, but password-changing operations cause accounts
with long hashes to revert to short hashes, and you cannot change them
back to long hashes while --old-passwords is in effect.
An upgrade to MySQL 4.1 can cause a compatibility issue for
applications that use PASSWORD() to generate passwords for their own
purposes. (Applications really should not do this, because PASSWORD()
should be used only to manage passwords for MySQL accounts. But some
applications use PASSWORD() for their own purposes anyway.) If you upgrade to
4.1 and run the server under conditions where it generates long password
hashes, an application that uses PASSWORD() for its own passwords will
break. The recommended course of action is to modify the application to
use another function such as SHA1() or MD5() to produce hashed values.
If that is not possible, you can use the OLD_PASSWORD() function, which
is provided to generate short hashes in the old format. (But note that
OLD_PASSWORD() may one day no longer be supported.)
If the server is running under circumstances where it generates short hashes,
OLD_PASSWORD() is available but is equivalent to PASSWORD().
Password hashing in MySQL 4.1.0 differs from hashing in 4.1.1 and up. The 4.1.0 differences are:
PASSWORD() function is non-repeatable. That is, with a given
argument X, successive calls to PASSWORD(X) generate different
results.
Access denied Errors
If you encounter Access denied errors when you try to connect to the
MySQL server, the following list indicates some courses of
action you can take to correct the problem:
mysql_install_db
script to set up the initial grant table contents? If not, do so.
See section 4.3.4 Setting Up the Initial MySQL Privileges. Test the 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.MYD' in the MySQL database directory. Ordinarily, this is `PATH/var/mysql/user.MYD', 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. That is also a security risk, so 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 a
User column value of '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 an entry for your
host.
shell> mysqladmin -u root -pxxxx ver Access denied for user: 'root@localhost' (Using password: YES)It means that you are using a wrong password. See section 4.3.7 Setting Up Passwords. If you have forgot the root password, you can restart
mysqld with
--skip-grant-tables to change the password.
See section A.4.2 How to Reset a Forgotten Root Password.
If you get the above error even if you haven't specified a password,
this means that you a wrong password in some my.ini
file. See section 4.1.2 `my.cnf' Option Files. You can avoid using option files with the --no-defaults option, as follows:
shell> mysqladmin --no-defaults -u root ver
mysql_fix_privilege_tables script? If not, do so. The structure of
the grant tables changed with MySQL Version 3.22.11 when the
GRANT statement became functional.
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 ... IDENTIFIED BY statement or the mysqladmin
password command.
See section 4.3.7 Setting 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
using a MySQL version prior to 3.23.27 that uses MIT-pthreads
(localhost connections are made using Unix sockets, which were not
supported by MIT-pthreads at that time). 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. For example if you get an error
message that contains Using password: NO, this means that you
tried to login without an password.
user table that matches that host:
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, db, or host
table for the user/hostname combination from which you are trying to
connect and then execute mysqladmin flush-privileges. If you are
not running MySQL Version 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.)
Another reason for this error on Linux is that you are using a binary
MySQL version that is compiled with a different glibc version
than the one you are using. In this case you should either upgrade your
OS/glibc or download the source MySQL version and compile this
yourself. A source RPM is normally trivial to compile and install, so
this isn't a big problem.
shell> mysqladmin -u root -pxxxx -h some-hostname ver Access denied for user: 'root@' (Using password: YES)This means that MySQL got some error when trying to resolve the IP to a hostname. In this case you can execute
mysqladmin
flush-hosts to reset the internal DNS cache. See section 5.5.5 How MySQL uses DNS.
Some permanent solutions are:
mysqld with --skip-name-resolve.
mysqld with --skip-host-cache.
localhost if you are running the server and the client
on the same machine.
/etc/hosts.
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 -h 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=''. Because 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 Host='localhost' and
User=''.
db or
host table:
Access to database deniedIf 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 which hosts the db table entry
applies to.
If you get the error when 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.