How to Migrate MySQL User Privileges to a New Server: Export and Import Guide


1 views

When migrating MySQL servers, simply copying the mysql.user table isn't always sufficient. MySQL stores user privileges across multiple tables in the mysql database:

mysql.user (user accounts and global privileges)
mysql.db (database-level privileges)
mysql.tables_priv (table-level privileges)
mysql.columns_priv (column-level privileges)
mysql.procs_priv (stored procedure privileges)

Use mysqldump to properly export all privilege-related tables:

mysqldump --all-databases --routines --no-data --lock-all-tables \
--host=old-server --user=admin --password > mysql_privileges.sql

This command exports:

  • All database structures without data (--no-data)
  • Stored procedures (--routines)
  • User privileges across all tables

If you only need user accounts and passwords:

mysqldump mysql user --host=old-server --user=admin --password > mysql_users.sql

For complete privilege migration:

mysqldump mysql user db tables_priv columns_priv procs_priv \
--host=old-server --user=admin --password > full_privileges.sql

After transferring the dump file to the new server:

mysql --host=new-server --user=root --password < mysql_privileges.sql

Then flush privileges to apply changes:

mysqladmin --host=new-server --user=root --password flush-privileges

Check user privileges on the new server:

SELECT * FROM mysql.user;
SHOW GRANTS FOR 'username'@'host';
  • MySQL versions must be compatible (5.7 to 5.7, not 5.7 to 8.0)
  • Password hashing algorithms may differ between versions
  • Test the migration in a staging environment first

For regular migrations, consider this bash script:

#!/bin/bash
# MySQL Privilege Migration Script

OLD_HOST="old.mysql.server"
NEW_HOST="new.mysql.server"
MYSQL_USER="admin"
MYSQL_PASS="securepassword"
DUMP_FILE="/tmp/mysql_privileges_$(date +%Y%m%d).sql"

# Export privileges
mysqldump --host=$OLD_HOST --user=$MYSQL_USER --password=$MYSQL_PASS \
--all-databases --routines --no-data --lock-all-tables > $DUMP_FILE

# Import to new server
mysql --host=$NEW_HOST --user=$MYSQL_USER --password=$MYSQL_PASS < $DUMP_FILE

# Flush privileges
mysqladmin --host=$NEW_HOST --user=$MYSQL_USER --password=$MYSQL_PASS flush-privileges

echo "Migration completed. Verify with: SHOW GRANTS FOR 'user'@'host'"

When migrating MySQL servers, simply copying the mysql.user table isn't sufficient due to:

  • Password hash variations between MySQL versions
  • Potential privilege table structure changes
  • System-specific metadata conflicts

Method 1: Using mysqldump for System Tables

mysqldump --all-databases --routines --triggers --no-create-info --no-data \
--ignore-table=mysql.user --ignore-table=mysql.db --ignore-table=mysql.tables_priv \
--ignore-table=mysql.columns_priv --ignore-table=mysql.procs_priv \
--ignore-table=mysql.proxies_priv > privileges.sql

Method 2: SHOW GRANTS Command

Generate privilege statements for all users:

mysql -B -N -e "SELECT CONCAT('SHOW GRANTS FOR ''',user,'''@''',host,''';') \
FROM mysql.user WHERE user NOT IN ('root','mysql.sys','mysql.session','mysql.infoschema')" \
| mysql | sed 's/$/;/' > all_grants.sql

Method 3: pt-show-grants (Percona Toolkit)

pt-show-grants --host oldserver --user admin --password > grants.sql
mysql --host newserver --user admin --password < grants.sql

For MySQL 5.7+ to 8.0+ migrations:

# On old server (5.7):
ALTER USER 'appuser'@'%' IDENTIFIED WITH mysql_native_password BY 'password';

# Then use SHOW GRANTS or pt-show-grants to export

After migration, verify consistency:

mysql -e "SELECT user,host,authentication_string FROM mysql.user"
mysql -e "SHOW GRANTS FOR 'appuser'@'%'"
  • Missing FLUSH PRIVILEGES after import
  • Version-specific authentication plugins
  • Hostname resolution differences
  • Missing global privileges (REQUIRE SSL, etc.)

Example bash script for complete migration:

#!/bin/bash
OLD_HOST="db1.example.com"
NEW_HOST="db2.example.com"
CREDS="-u root -p${MYSQL_PWD}"

# Export grants
mysql ${CREDS} -h ${OLD_HOST} -N -e \
"SELECT CONCAT('SHOW GRANTS FOR ''',user,'''@''',host,''';') \
FROM mysql.user WHERE user NOT LIKE 'mysql.%'" \
| mysql ${CREDS} -h ${OLD_HOST} \
| sed 's/$/;/' \
| grep -v "Grants for" > mysql_grants.sql

# Import to new server
mysql ${CREDS} -h ${NEW_HOST} < mysql_grants.sql
mysql ${CREDS} -h ${NEW_HOST} -e "FLUSH PRIVILEGES"

echo "Migration completed. Verify privileges on new server."