MySQL Secure Deployment Guide  /  Post Installation Setup

Chapter 5 Post Installation Setup

Post-installation setup involves creating a safe directory for import and export operations, configuring server startup options, initializing the data directory, starting MySQL using systemd, resetting the password for the MySQL root@localhost user account, and running a few tests to ensure that the server is working.

Creating a Safe Directory For Import and Export Operations

MySQL users with the FILE privilege have permission to read and write files on the server host using LOAD DATA INFILE and SELECT ... INTO OUTFILE statements, and the LOAD_FILE() function. By default, a user who has the FILE privilege can read any file on the server host that is either world-readable or readable by the MySQL server. (This implies the user can read any file in any database directory, because the server can access any of those files.) The FILE privilege also enables the user to create new files in any directory where the MySQL server has write access. This includes the server data directory containing the files that implement the privilege tables.

To limit the scope of the FILE privilege, create a directory that users with the FILE privilege can safely use for import and export operations. In this deployment, the directory created is named mysql-files and is located under the data directory. In a later step, when server startup options are configured, the secure_file_priv option is set to the mysql-files directory.

$> cd /usr/local/mysql  
$> mkdir mysql-files
$> chown mysql:mysql mysql-files
$> chmod 750 mysql-files

Configuring Server Startup Options

Specify options that the MySQL server should use at startup by placing them in a MySQL configuration file. If you do not do this, the server starts with its default settings (see Server Configuration Defaults).

Note

Certain InnoDB options can only be configured before initializing the data directory. Among these options are innodb_data_home_dir, innodb_data_file_path, innodb_log_file_size, innodb_log_group_home_dir, and innodb_page_size. If you do not want to use default values for these options, set your own values in the MySQL configuration file before initializing the data directory. This deployment uses default InnoDB configuration settings. For more information, see InnoDB Startup Configuration.

  1. To create a MySQL configuration file, issue these commands as root:

    $> cd /etc
    $> touch my.cnf
    $> chown root:root my.cnf  
    $> chmod 644 my.cnf
    Note

    If there is an existing my.cnf configuration file in the same location that belongs to another MySQL instance, use a different name for your configuration file.

  2. Under a [mysqld] group entry, set the datadir, socket, port, log-error options for the instance. If there are other MySQL installations on the host, ensure that the values for these options are unique to this instance. This deployment uses the default values.

    [mysqld]
    datadir=/usr/local/mysql/data
    socket=/tmp/mysql.sock
    port=3306
    log-error=/usr/local/mysql/data/localhost.localdomain.err
    Important

    The location of the MySQL data directory is critically important to the security of a MySQL installation. In addition to user data, the data directory contains data dictionary and system tables, which store sensitive information about database objects, users, privileges, and so on. Following the principle of least privilege, system user access to the data directory should be as restrictive as possible. The size of the file system where the data directory resides should also be considered. Ensure that the file system can accommodate the anticipated size of your data. The deployment described in this guide places the data directory in the default location (/usr/local/mysql/data), and access to the directory is limited to the mysql operating system user account.

  3. Set the user option to ensure that the server is started as the unprivileged mysql user account. For security reasons, it is important to avoid running the server as the operating system root user.

    user=mysql
  4. If you intend to permit import and export operations, set the secure_file_priv system variable to the path of the mysql-files directory that you created previously. This option limits file import and export operations, such as those performed by the LOAD DATA and SELECT ... INTO OUTFILE statements and the LOAD_FILE() function, to the specified directory. If you do not intend to permit import or export operations, set secure_file_priv to NULL, which disables import and export operations entirely. NULL is the default setting.

    secure_file_priv=/usr/local/mysql/mysql-files
  5. To avoid potential security issues with the LOCAL version of LOAD DATA, ensure that local_infile is disabled, which it is by default.

    local_infile=OFF

    For more information, see Security Considerations for LOAD DATA LOCAL.

After completing the steps above, the configuration file should contain these settings, assuming you have not added others:

[mysqld]
datadir=/usr/local/mysql/data
socket=/tmp/mysql.sock
port=3306
log-error=/usr/local/mysql/data/localhost.localdomain.err
user=mysql
secure_file_priv=/usr/local/mysql/mysql-files
local_infile=OFF

Initializing the Data Directory

After installing MySQL, you must initialize the data directory, which includes the mysql system database and its tables, including grant tables, server-side help tables, and time zone tables. Initialization also creates the root@localhost superuser account and the InnoDB system tablespace and related data structures required to manage InnoDB tables.

To initialize the data directory:

  1. Change location to the top-level directory of the MySQL installation, create the data directory, and grant ownership to the mysql user.

    $> cd /usr/local/mysql
    $> mkdir data
    $> chmod 750 data
    $> chown mysql:mysql data
    Note

    Data directory ownership is assigned to the mysql user, but most of the MySQL installation remains owned by root. Other exceptions are the error log file, the mysql-files directory, the pid file, and socket file, to which the mysql user must have write access. Files and resources that the mysql user requires read access to include configuration files (e.g., /etc/my.cnf) and the MySQL binaries (/usr/local/mysql/bin).

  2. Initialize the data directory.

    $> cd /usr/local/mysql
    $> bin/mysqld --defaults-file=/etc/my.cnf --initialize

    Initialization output is printed to the error log (/usr/local/mysql/data/localhost.localdomain.err) and appears similar to the output shown below. The output includes an initial random password for the root@localhost account. The password is required later to reset the root@localhost password.

    2018-05-02T17:47:49.806563Z 0 [System] [MY-013169] [Server] 
    /usr/local/mysql-commercial-8.0.11-linux-glibc2.12-x86_64/bin/mysqld (mysqld 8.0.11-commercial) 
    initializing of server in progress as process 16039
    2018-05-02T17:47:54.083010Z 5 [Note] [MY-010454] [Server] 
    A temporary password is generated for root@localhost: uZmx9ihSd2;.
    2018-05-02T17:47:56.225881Z 0 [System] [MY-013170] [Server] 
    /usr/local/mysql-commercial-8.0.11-linux-glibc2.12-x86_64/bin/mysqld (mysqld 8.0.11-commercial) 
    initializing of server has completed
Note

Data directory initialization creates time zone tables in the mysql database but does not populate them. To do so, refer to the instructions in MySQL Server Time Zone Support.

For more information about data directory initialization, see Initializing the Data Directory.

Starting the Server using systemd

This section describes how to start the server with systemd and how to enable automatic restart of the MySQL server when the host is rebooted.

systemd provides manual server management using the systemctl command:

systemctl {start|stop|restart|status} mysqld

To configure the MySQL installation to work with systemd:

  1. Add a systemd service unit configuration file with details about the MySQL service. The file is named mysqld.service and is placed in /usr/lib/systemd/system.

    $> cd /usr/lib/systemd/system
    $> touch mysqld.service
    $> chmod 644 mysqld.service

    Add this configuration information to the mysqld.service file:

    [Unit]
    Description=MySQL Server
    Documentation=man:mysqld(8)
    Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
    After=network.target
    After=syslog.target
    
    [Install]
    WantedBy=multi-user.target
    
    [Service]
    User=mysql
    Group=mysql
    
    # Have mysqld write its state to the systemd notify socket
    Type=notify
    
    # Disable service start and stop timeout logic of systemd for mysqld service.
    TimeoutSec=0
    
    # Start main service
    ExecStart=/usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf $MYSQLD_OPTS 
    
    # Use this to switch malloc implementation
    EnvironmentFile=-/etc/sysconfig/mysql
    
    # Sets open_files_limit
    LimitNOFILE = 10000
    
    Restart=on-failure
    
    RestartPreventExitStatus=1
    
    # Set environment variable MYSQLD_PARENT_PID. This is required for restart.
    Environment=MYSQLD_PARENT_PID=1
    
    PrivateTmp=false
  2. Enable the mysqld service to automatically start at reboot.

    $> systemctl enable mysqld.service
    Created symlink from /etc/systemd/system/multi-user.target.wants/mysqld.service 
    to /usr/lib/systemd/system/mysqld.service.
  3. To ensure the systemd configuration works, start the mysqld service manually using systemctl.

    $> systemctl start mysqld
  4. Check the status of the mysqld service. The output should appear similar to the following, which shows that the mysqld service was started successfully.

    $> systemctl status mysqld
    ● mysqld.service - MySQL Server
       Loaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; vendor preset: disabled)
       Active: active (running) since Wed 2018-05-02 18:18:05 ADT; 5s ago
         Docs: man:mysqld(8)
               http://dev.mysql.com/doc/refman/en/using-systemd.html
     Main PID: 19520 (mysqld)
       Status: "SERVER_OPERATING"
       CGroup: /system.slice/mysqld.service
               └─19520 /usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf
    
    May 02 18:18:04 localhost.localdomain systemd[1]: Starting MySQL Server...
    May 02 18:18:05 localhost.localdomain systemd[1]: Started MySQL Server.
  5. To verify that systemd automatically starts MySQL when the system is rebooted, restart your system and check the status of the mysqld service again.

    $> systemctl status mysqld
Note

systemd has its own log file which can be accessed using journalctl. To view mysqld-related log messages, use journalctl -u mysqld. Some messages, such as MySQL startup messages, may be printed to the systemd log.

For more information about systemd, see Managing MySQL Server with systemd.

Resetting the MySQL root Account Password

This procedure assumes that the MySQL server is running. You can check server status by issuing:

$> systemctl status mysqld

When the data directory was initialized, a random initial password was generated for the MySQL root account (root@localhost) and marked as expired. Perform these steps to set a new password:

  1. Using the mysql client, connect to the server as root@localhost using the random password that the server generated during the initialization sequence:

    $> cd /usr/local/mysql 
    $> bin/mysql -u root -p
    Enter password: (enter the random root password here)
  2. After connecting, assign a new root@localhost password. Use a strong password. Ideally, the password should conform to the password policy that you will define using the validate_password component, which is enabled in a later step. (See Chapter 6, Installing the MySQL Password Validation Component.)

    mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'password';

    Alternatively, you can generate a random password using the RANDOM PASSWORD option. For more information, see Random Password Generation.

Testing the Server

Now that MySQL is installed and initialized, and the MySQL root user password is reset, perform a couple of simple tests to verify that the server works.

  1. Use mysqlshow to verify that you can retrieve information from the server.

    $> cd /usr/local/mysql 
    $> bin/mysqlshow -u root -p
    Enter password: (enter root password here)
    +--------------------+
    |     Databases      |
    +--------------------+
    | information_schema |
    | mysql              |
    | performance_schema |
    | sys                |
    +--------------------+
  2. Use mysqladmin to view MySQL server version information.

    $> cd /usr/local/mysql 
    $> bin/mysqladmin -u root -p version
    Enter password: (enter root password here)

    The output should be similar to that shown here:

    bin/mysqladmin  Ver 8.0.19-commercial for linux-glibc2.12 on x86_64 
    (MySQL Enterprise Server - Commercial)
    Copyright (c) 2000, 2020, Oracle and/or its affiliates.
    
    Oracle is a registered trademark of Oracle Corporation and/or its
    affiliates. Other names may be trademarks of their respective
    owners.
    
    Server version		8.0.19-commercial
    Protocol version	10
    Connection		Localhost via UNIX socket
    UNIX socket		/tmp/mysql.sock
    Uptime:			11 min 7 sec
    
    Threads: 3  Questions: 8  Slow queries: 0  Opens: 146  Flush tables: 3  
    Open tables: 63  Queries per second avg: 0.011

For additional tests, see Testing the Server.