April 2018 is not just a date for the MySQL world. MySQL 8.0 was released there, and more than 1 year after, it’s probably time to consider migrating to this new version.
MySQL 8.0 has important performance and security improvements, and, as in all migration to a new database version, there are several things to take into account before going into production to avoid hard issues like data loss, excessive downtime, or even a rollback during the migration task.
In this blog, we’ll mention some of the new MySQL 8.0 features, some deprecated stuff, and what you need to keep in mind before migrating.
What’s New in MySQL 8.0?
Let’s now summarize some of the most important features mentioned in the official documentation for this new MySQL version.
- MySQL incorporates a transactional data dictionary that stores information about database objects.
- An atomic DDL statement combines the data dictionary updates, storage engine operations, and binary log writes associated with a DDL operation into a single, atomic transaction.
- The MySQL server automatically performs all necessary upgrade tasks at the next startup to upgrade the system tables in the mysql schema, as well as objects in other schemas such as the sys schema and user schemas. It is not necessary for the DBA to invoke mysql_upgrade.
- It supports the creation and management of resource groups, and permits assigning threads running within the server to particular groups so that threads execute according to the resources available to the group.
- Table encryption can now be managed globally by defining and enforcing encryption defaults. The default_table_encryption variable defines an encryption default for newly created schemas and general tablespace. Encryption defaults are enforced by enabling the table_encryption_privilege_check variable.
- The default character set has changed from latin1 to utf8mb4.
- It supports the use of expressions as default values in data type specifications. This includes the use of expressions as default values for the BLOB, TEXT, GEOMETRY, and JSON data types.
- Error logging was rewritten to use the MySQL component architecture. Traditional error logging is implemented using built-in components, and logging using the system log is implemented as a loadable component.
- A new type of backup lock permits DML during an online backup while preventing operations that could result in an inconsistent snapshot. The new backup lock is supported by LOCK INSTANCE FOR BACKUP and UNLOCK INSTANCE syntax. The BACKUP_ADMIN privilege is required to use these statements.
- MySQL Server now permits a TCP/IP port to be configured specifically for administrative connections. This provides an alternative to the single administrative connection that is permitted on the network interfaces used for ordinary connections even when max_connections connections are already established.
- It supports invisible indexes. This index is not used by the optimizer and makes it possible to test the effect of removing an index on query performance, without removing it.
- Document Store for developing both SQL and NoSQL document applications using a single database.
- MySQL 8.0 makes it possible to persist global, dynamic server variables using the SET PERSIST command instead of the usual SET GLOBAL one.
MySQL Security and Account Management
As there are many improvements related to security and user management, we’ll list them in a separate section.
- The grant tables in the mysql system database are now InnoDB tables.
- The new caching_sha2_password authentication plugin is now the default authentication method in MySQL 8.0. It implements SHA-256 password hashing, but uses caching to address latency issues at connect time. It provides more secure password encryption than the mysql_native_password plugin, and provides better performance than sha256_password.
- MySQL now supports roles, which are named collections of privileges. Roles can have privileges granted to and revoked from them, and they can be granted to and revoked from user accounts.
- MySQL now maintains information about password history, enabling restrictions on reuse of previous passwords.
- It enables administrators to configure user accounts such that too many consecutive login failures due to incorrect passwords cause temporary account locking.
As the previous point, there are also many improvements related to this topic, so we’ll list them in a separate section too.
- The current maximum auto-increment counter value is written to the redo log each time the value changes, and saved to an engine-private system table on each checkpoint. These changes make the current maximum auto-increment counter value persistent across server restarts
- When encountering index tree corruption, InnoDB writes a corruption flag to the redo log, which makes the corruption flag crash-safe. InnoDB also writes in-memory corruption flag data to an engine-private system table on each checkpoint. During recovery, InnoDB reads corruption flags from both locations and merges results before marking in-memory table and index objects as corrupt.
- A new dynamic variable, innodb_deadlock_detect, may be used to disable deadlock detection. On high concurrency systems, deadlock detection can cause a slowdown when numerous threads wait for the same lock. At times, it may be more efficient to disable deadlock detection and rely on the innodb_lock_wait_timeout setting for transaction rollback when a deadlock occurs.
- InnoDB temporary tables are now created in the shared temporary tablespace, ibtmp1.
- mysql system tables and data dictionary tables are now created in a single InnoDB tablespace file named mysql.ibd in the MySQL data directory. Previously, these tables were created in individual InnoDB tablespace files in the mysql database directory.
- By default, undo logs now reside in two undo tablespaces that are created when the MySQL instance is initialized. Undo logs are no longer created in the system tablespace.
- The new innodb_dedicated_server variable, which is disabled by default, can be used to have InnoDB automatically configure the following options according to the amount of memory detected on the server: innodb_buffer_pool_size, innodb_log_file_size, and innodb_flush_method. This option is intended for MySQL server instances that run on a dedicated server.
- Tablespace files can be moved or restored to a new location while the server is offline using the innodb_directories option.
Now, let’s take a look at some of the features that you shouldn’t use anymore in this new MySQL version.
What is Deprecated in MySQL 8.0?
The following features are deprecated and will be removed in a future version.
- The utf8mb3 character set is deprecated. Please use utf8mb4 instead.
- Because caching_sha2_password is the default authentication plugin in MySQL 8.0 and provides a superset of the capabilities of the sha256_password authentication plugin, sha256_password is deprecated.
- The validate_password plugin has been reimplemented to use the server component infrastructure. The plugin form of validate_password is still available but is deprecated.
- The ENGINE clause for the ALTER TABLESPACE and DROP TABLESPACE statements.
- The PAD_CHAR_TO_FULL_LENGTH SQL mode.
- AUTO_INCREMENT support is deprecated for columns of type FLOAT and DOUBLE (and any synonyms). Consider removing the AUTO_INCREMENT attribute from such columns, or convert them to an integer type.
- The UNSIGNED attribute is deprecated for columns of type FLOAT, DOUBLE, and DECIMAL (and any synonyms). Consider using a simple CHECK constraint instead for such columns.
- FLOAT(M,D) and DOUBLE(M,D) syntax to specify the number of digits for columns of type FLOAT and DOUBLE (and any synonyms) is a nonstandard MySQL extension. This syntax is deprecated.
- The nonstandard C-style &&, ||, and ! operators that are synonyms for the standard SQL AND, OR, and NOT operators, respectively, are deprecated. Applications that use the nonstandard operators should be adjusted to use the standard operators.
- The mysql_upgrade client is deprecated because its capabilities for upgrading the system tables in the mysql system schema and objects in other schemas have been moved into the MySQL server.
- The mysql_upgrade_info file, which is created data directory and used to store the MySQL version number.
- The relay_log_info_file system variable and –master-info-file option are deprecated. Previously, these were used to specify the name of the relay log info log and master info log when relay_log_info_repository=FILE and master_info_repository=FILE were set, but those settings have been deprecated. The use of files for the relay log info log and master info log has been superseded by crash-safe slave tables, which are the default in MySQL 8.0.
- The use of the MYSQL_PWD environment variable to specify a MySQL password is deprecated.
And now, let’s take a look at some of the features that you must stop using in this MySQL version.
What Was Removed in MySQL 8.0?
The following features have been removed in MySQL 8.0.
- The innodb_locks_unsafe_for_binlog system variable was removed. The READ COMMITTED isolation level provides similar functionality.
- Using GRANT to create users. Instead, use CREATE USER. Following this practice makes the NO_AUTO_CREATE_USER SQL mode immaterial for GRANT statements, so it too is removed, and an error now is written to the server log when the presence of this value for the sql_mode option in the options file prevents mysqld from starting.
- Using GRANT to modify account properties other than privilege assignments. This includes authentication, SSL, and resource-limit properties. Instead, establish such properties at account-creation time with CREATE USER or modify them afterward with ALTER USER.
- IDENTIFIED BY PASSWORD ‘auth_string’ syntax for CREATE USER and GRANT. Instead, use IDENTIFIED WITH auth_plugin AS ‘auth_string’ for CREATE USER and ALTER USER, where the ‘auth_string’ value is in a format compatible with the named plugin.
- The PASSWORD() function. Additionally, PASSWORD() removal means that SET PASSWORD … = PASSWORD(‘auth_string’) syntax is no longer available.
- The old_passwords system variable.
- The FLUSH QUERY CACHE and RESET QUERY CACHE statements.
- These system variables: query_cache_limit, query_cache_min_res_unit, query_cache_size, query_cache_type, query_cache_wlock_invalidate.
- These status variables: Qcache_free_blocks, Qcache_free_memory, Qcache_hits, Qcache_inserts, Qcache_lowmem_prunes, Qcache_not_cached, Qcache_queries_in_cache, Qcache_total_blocks.
- These thread states: checking privileges on cached query, checking query cache for a query, invalidating query cache entries, sending cached result to the client, storing result in the query cache, Waiting for query cache lock.
- The tx_isolation and tx_read_only system variables have been removed. Use transaction_isolation and transaction_read_only instead.
- The sync_frm system variable has been removed because .frm files have become obsolete.
- The secure_auth system variable and –secure-auth client option have been removed. The MYSQL_SECURE_AUTH option for the mysql_options() C API function was removed.
- The log_warnings system variable and –log-warnings server option have been removed. Use the log_error_verbosity system variable instead.
- The global scope for the sql_log_bin system variable was removed. sql_log_bin has session scope only, and applications that rely on accessing @@GLOBAL.sql_log_bin should be adjusted.
- The unused date_format, datetime_format, time_format, and max_tmp_tables system variables are removed.
- The deprecated ASC or DESC qualifiers for GROUP BY clauses are removed. Queries that previously relied on GROUP BY sorting may produce results that differ from previous MySQL versions. To produce a given sort order, provide an ORDER BY clause.
- The parser no longer treats N as a synonym for NULL in SQL statements. Use NULL instead. This change does not affect text file import or export operations performed with LOAD DATA or SELECT … INTO OUTFILE, for which NULL continues to be represented by N.
- The client-side –ssl and –ssl-verify-server-cert options have been removed. Use –ssl-mode=REQUIRED instead of –ssl=1 or –enable-ssl. Use –ssl-mode=DISABLED instead of –ssl=0, –skip-ssl, or –disable-ssl. Use –ssl-mode=VERIFY_IDENTITY instead of –ssl-verify-server-cert options.
- The mysql_install_db program has been removed from MySQL distributions. Data directory initialization should be performed by invoking mysqld with the –initialize or –initialize-insecure option instead. In addition, the –bootstrap option for mysqld that was used by mysql_install_db was removed, and the INSTALL_SCRIPTDIR CMake option that controlled the installation location for mysql_install_db was removed.
- The mysql_plugin utility was removed. Alternatives include loading plugins at server startup using the –plugin-load or –plugin-load-add option, or at runtime using the INSTALL PLUGIN statement.
- The resolveip utility is removed. nslookup, host, or dig can be used instead.
There are a lot of new, deprecated, and removed features. You can check the official website for more detailed information.
Considerations Before Migrating to MySQL 8.0
Let’s mention now some of the most important things to consider before migrating to this MySQL version.
As we mentioned, caching_sha2_password is not the default authentication method, so you should check if your application/connector supports it. If not, let’s see how you can change the default authentication method and the user authentication plugin to ‘mysql_native_password’ again.
To change the default authentication method, edit the my.cnf configuration file, and add/edit the following line:
$ vi /etc/my.cnf [mysqld] default_authentication_plugin=mysql_native_password
To change the user authentication plugin, run the following command with a privileged user:
$ mysql -p ALTER USER ‘username’@’hostname’ IDENTIFIED WITH ‘mysql_native_password’ BY ‘password’;
Anyway, these changes aren’t a permanent solution as the old authentication could be deprecated soon, so you should take it into account for a future database upgrade.
Also the roles are an important feature here. You can reduce the individual privileges assigning it to a role and adding the corresponding users there.
For example, you can create a new role for the marketing and the developers teams:
$ mysql -p CREATE ROLE 'marketing', 'developers';
Assign privileges to these new roles:
GRANT SELECT ON *.* TO 'marketing'; GRANT ALL PRIVILEGES ON *.* TO 'developers';
And then, assign the role to the users:
GRANT 'marketing' TO 'marketing1'@'%'; GRANT 'marketing' TO 'marketing2'@'%'; GRANT 'developers' TO 'developer1'@'%';
And that’s it. You’ll have the following privileges:
SHOW GRANTS FOR 'marketing1'@'%'; +-------------------------------------------+ | Grants for marketing1@% | +-------------------------------------------+ | GRANT USAGE ON *.* TO `marketing1`@`%` | | GRANT `marketing`@`%` TO `marketing1`@`%` | +-------------------------------------------+ 2 rows in set (0.00 sec) SHOW GRANTS FOR 'marketing'; +----------------------------------------+ | Grants for marketing@% | +----------------------------------------+ | GRANT SELECT ON *.* TO `marketing`@`%` | +----------------------------------------+ 1 row in set (0.00 sec)
As the new default character set is utf8mb4, you should make sure you’re not using the default one as it’ll change.
To avoid some issues, you should specify the character_set_server and the collation_server variables in the my.cnf configuration file.
$ vi /etc/my.cnf [mysqld] character_set_server=latin1 collation_server=latin1_swedish_ci
The MySQL privilege tables in the MySQL schema are moved to InnoDB. You can create a table engine=MyISAM, and it will work as before, but coping a MyISAM table into a running MySQL server will not work because it will not be discovered.
There must be no partitioned tables that use a storage engine that does not have native partitioning support. You can run the following query to verify this point.
$ mysql -p SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE ENGINE NOT IN ('innodb', 'ndbcluster') AND CREATE_OPTIONS LIKE '%partitioned%';
If you need to change the engine of a table, you can run:
ALTER TABLE table_name ENGINE = INNODB;
As a last step, you can run the mysqlcheck command using the check-upgrade flag to confirm if everything looks fine.
$ mysqlcheck -uroot -p --all-databases --check-upgrade Enter password: mysql.columns_priv OK mysql.component OK mysql.db OK mysql.default_roles OK mysql.engine_cost OK mysql.func OK mysql.general_log OK mysql.global_grants OK mysql.gtid_executed OK mysql.help_category OK mysql.help_keyword OK mysql.help_relation OK mysql.help_topic OK mysql.innodb_index_stats OK mysql.innodb_table_stats OK mysql.password_history OK mysql.plugin OK mysql.procs_priv OK mysql.proxies_priv OK mysql.role_edges OK mysql.server_cost OK mysql.servers OK mysql.slave_master_info OK mysql.slave_relay_log_info OK mysql.slave_worker_info OK mysql.slow_log OK mysql.tables_priv OK mysql.time_zone OK mysql.time_zone_leap_second OK mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK sys.sys_config OK world_x.city OK world_x.country OK world_x.countryinfo OK world_x.countrylanguage OK
There are several things to check before performing the upgrade. You can check the official MySQL documentation for more detailed information.
There are different ways to upgrade MySQL 5.7 to 8.0. You can use the upgrade in-place or even create a replication slave in the new version, so you can promote it later.
But before upgrading, step 0 must be backing up your data. The backup should include all the databases including the system databases. So, if there is any issue, you can rollback asap.
Another option, depending on the available resources, can be creating a cascade replication MySQL 5.7 -> MySQL 8.0 -> MySQL 5.7, so after promoting the new version, if something went wrong, you can promote the slave node with the old version back. But it could be dangerous if there was some issue with the data, so the backup is a must before it.
For any method to be used, it’s necessary a test environment to verify that the application is working without any issue using the new MySQL 8.0 version.
More than 1 year after the MySQL 8.0 release, it is time to start thinking to migrate your old MySQL version, but luckily, as the end of support for MySQL 5.7 is 2023, you have time to create a migration plan and test the application behavior with no rush. Spending some time in that testing step is necessary to avoid any issue after migrating it.