Databases (MySQL / phpMyAdmin)

Streamlined Bulk MySQL/MariaDB User Recovery: Your Complete Backup File Manual

By the Domain India teamPublished 6 min read
Knowledge base article
Contents (8 sections)

When you rebuild a database server, you often have the databases but not the user accounts that connect to them. This guide shows how to turn a folder of per-user backup files into one SQL script that recreates every MySQL or MariaDB user with its original password hash.

Key takeaways

Put the backup files in one folder, run the shell script below to generate database_user_restore.sql, read the generated file, then load it with mysql -u root -p < database_user_restore.sql. The script keeps each user's original host and password hash, and restores the grants found in each file instead of giving everyone full access. Check the result with SELECT user, host, plugin FROM mysql.user; and SHOW GRANTS.

Own server only

These steps need root on your own server, such as a VPS. They don't apply to Domain India shared hosting, where the server is managed for you and database users are created from your control panel.

1. Prepare the backup files

Collect the user backup files in one folder, for example:

The script expects each file to contain lines in this form. Check one of your files with cat first, and adjust the script if your format is different.

text
name: appuser@localhost
password: *6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4
GRANT SELECT, INSERT, UPDATE, DELETE ON `appdb`.* TO 'appuser'@'localhost';
  • name: the user and the host it connects from.
  • password: the stored password hash, not the plain password.
  • GRANT lines: the privileges to restore. If your files have none, you will add grants by hand in step 5.

Keep the folder readable by root only (chmod 700 /root/database_user), because password hashes can be attacked offline.

2. Create the restore script

  1. Log in to the server over SSH as root.
  2. Create the script file: nano /root/restore_mysql_users.sh
  3. Paste the script below into the file.
  4. Save and exit: press Ctrl+X, then Y, then Enter.
  5. Make it executable: chmod +x /root/restore_mysql_users.sh
bash
#!/bin/bash
set -euo pipefail

# Folder with the *.mysql.user backup files
USER_BACKUP_PATH="/root/database_user"

# SQL file the script will write
OUTPUT_SQL="/root/database_user_restore.sql"

{
  echo "-- MySQL/MariaDB user restore script"
  echo "SET SQL_LOG_BIN=0;"
} > "$OUTPUT_SQL"

shopt -s nullglob
for userfile in "$USER_BACKUP_PATH"/*.mysql.user; do
  echo "Processing: $userfile"

  # "name: user@host" -> user and host
  NAME=$(grep -oP '^name:\s*\K\S+' "$userfile" || true)
  USERNAME="${NAME%@*}"
  HOSTNAME="${NAME#*@}"

  # "password: <hash>"
  PASSWORD_HASH=$(grep -oP '^password:\s*\K\S+' "$userfile" || true)

  if [[ -z "$NAME" || "$NAME" != *@* || -z "$PASSWORD_HASH" ]]; then
    echo "  Skipping: could not read name or password in $userfile"
    continue
  fi

  # Only 41-character hashes starting with * (mysql_native_password) can be restored this way
  if [[ ! "$PASSWORD_HASH" =~ ^\*[0-9A-Fa-f]{40}$ ]]; then
    echo "  Skipping $USERNAME@$HOSTNAME: hash is not mysql_native_password; reset this password by hand"
    continue
  fi

  {
    echo "DROP USER IF EXISTS '$USERNAME'@'$HOSTNAME';"
    echo "CREATE USER '$USERNAME'@'$HOSTNAME' IDENTIFIED WITH mysql_native_password AS '$PASSWORD_HASH';"
    grep -E '^GRANT ' "$userfile" || echo "-- No GRANT lines found for '$USERNAME'@'$HOSTNAME'; add grants by hand"
    echo ""
  } >> "$OUTPUT_SQL"

  echo "  Added: $USERNAME@$HOSTNAME"
done

echo "FLUSH PRIVILEGES;" >> "$OUTPUT_SQL"
chmod 600 "$OUTPUT_SQL"
echo "Restore script written to $OUTPUT_SQL"

What the script does:

  • It keeps each user's original host. An earlier version of this guide changed every host other than localhost to %, which silently allowed those users to connect from anywhere.
  • It copies the GRANT lines from each file instead of granting ALL PRIVILEGES ON *.* WITH GRANT OPTION, which would have made every restored user a full administrator.
  • SET SQL_LOG_BIN=0 keeps the changes out of the binary log, so they are not copied to replicas. Remove that line if you want replicas to receive the users too.

3. Run the script

bash
/root/restore_mysql_users.sh

It processes every .mysql.user file in the folder and writes /root/database_user_restore.sql. Read its messages for any users it skipped.

4. Review the generated SQL

bash
less /root/database_user_restore.sql

For each user you should see a DROP USER IF EXISTS line, a CREATE USER line with the hash, and that user's GRANT lines. The file ends with FLUSH PRIVILEGES. Look for any -- No GRANT lines found comments and decide what each of those users needs.

DROP USER removes existing accounts

If a user with the same name and host already exists on the server, it is dropped and recreated from the backup, along with its current grants. Test the file on a staging server first if the target server is already in use.

5. Load the users into the server

bash
mysql -u root -p < /root/database_user_restore.sql

Enter the MySQL root password when asked. On MariaDB the mariadb client works the same way. If a user had no grants in the backup, give them access to their own database only, for example:

sql
GRANT ALL PRIVILEGES ON `appdb`.* TO 'appuser'@'localhost';

6. Check the restored users

sql
SELECT user, host, plugin FROM mysql.user ORDER BY user;
SHOW GRANTS FOR 'appuser'@'localhost';

Then test a real login as one of the restored users, for example mysql -u appuser -p appdb. Delete the backup folder and the generated SQL file, or move them somewhere safe, once you have finished.

7. Version notes

ServerRestoring mysql_native_password hashes
MariaDB 10.x and 11.x (AlmaLinux and Rocky Linux)Works as shown
MySQL 5.7 and 8.0Works as shown
MySQL 8.4Plugin is disabled by default; enable it with mysql_native_password=ON in my.cnf, or reset these passwords
MySQL 9.xPlugin removed; users must be given new passwords

You can't turn a mysql_native_password hash into a caching_sha2_password one by changing the plugin name in the SQL. To move a user to the newer plugin, set a new password with ALTER USER 'appuser'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'new-password';.

If you are planning a server of your own for your databases, see VPS plans compared.

Frequently asked questions

Do I need the users' plain passwords to restore them?

No. The script restores the stored password hash, so users keep their existing passwords. You only need new passwords for hashes the script cannot restore.

Why did the script skip some users?

Either the file did not contain a readable name or password line, or the hash was not a mysql_native_password hash. Reset the password for those users by hand with ALTER USER or CREATE USER ... IDENTIFIED BY.

Why not grant all privileges to every restored user?

ALL PRIVILEGES ON . with GRANT OPTION makes a user a full administrator of every database. Restore only the grants each user had, or grant access to their own database.

Does this work on MariaDB?

Yes. MariaDB accepts the same CREATE USER ... IDENTIFIED WITH mysql_native_password AS statement, and mysql_native_password is its default plugin for these accounts.

Can I restore database users this way on Domain India shared hosting?

No. On shared hosting you don't have root access to MySQL. Create database users from your control panel instead, or ask support for help.

If you get stuck restoring users on your server, open a support ticket or use our 24/7 live chat.

Ready when you are

Get DirectAdmin hosting from ₹100/mo + GST

See plans

Was this article helpful?

Your answer helps us decide what to improve next.

Still need help? Open a support ticket and our team will reply.

Prefer an app? Add this site to your home screen.Get the app