» Tranfer all MySQL databases to another server

Recently I had to migrate all MySQL databases from one server to another. This was a one time only operation, so setting up replication wasn't an option. And restoring a backup on the new server involved more downtime than strictly necessary. I figured the most ideal way would be to dump the active MySQL directly into the new MySQL instance. And that's what I did.

Features

  • This often beats setting up replication if you want a quick & dirty solution.
  • Extremely fast because it injects the MySQL dump directly into the new MySQL database, hence it does not use additional diskspace or disk IO.
  • InnoDB proof.
  • By putting everything in one script we can instantly create snapshots with recent data. This allows you to focus on other issues that might pop up during a database migration.
  • And yes, you could schedule this script in the crontab and sync to a standby server for emergency failover. But consider replication or clustering instead.

Warning

Be careful, this script will drop any existing database on the receiving side it encounters. USE AT OWN RISK! This is heavy material and you could seriously mess up your system if you don't know what you're doing.

The Script

#!/bin/bash
# where your mysql commands are
CMD_MYSQL="/usr/bin/mysql"
CMD_MYSQLDUMP="/usr/bin/mysqldump"
 
# login credentials of the submitting side
DB_USER_FROM="root"
DB_PASS_FROM="passxxx"
DB_HOST_FROM="source.example.com"
 
# login credentials of the receiving side
DB_USER_TO="root"
DB_PASS_TO="passxxx"
DB_HOST_TO="destination.example.com"
 
# index all databases on the local (submitting) side
echo "database sync"
DATABASES=`echo "SHOW DATABASES;" | ${CMD_MYSQL} -p${DB_PASS_FROM} -u ${DB_USER_FROM} -h ${DB_HOST_FROM}`
 
# loop over all the databases
for DATABASE in $DATABASES; do
  # skip non-databases
  if [ "${DATABASE}" != "Database" ] && [ "${DATABASE}" != "information_schema" ]; then
    echo "transmitting ${DATABASE}"
    
    # create database on remote (receiving) side if it doesn't exist
    echo "CREATE DATABASE IF NOT EXISTS ${DATABASE}" | ${CMD_MYSQL} -p${DB_PASS_TO} -u ${DB_USER_TO} -h ${DB_HOST_TO}
    
    # dump the current database and pipe it directly to the remote (receiving) side to inject it
    ${CMD_MYSQLDUMP} -Q -B --create-options --delayed-insert --complete-insert --quote-names --add-drop-table -p${DB_PASS_FROM} -u${DB_USER_FROM} -h${DB_HOST_FROM} ${DATABASE} | ${CMD_MYSQL} -p${DB_PASS_TO} -u ${DB_USER_TO} -h ${DB_HOST_TO} ${DATABASE}
  fi
done

Save this script somewhere (I usually take the /root/bin dir for this). Make it executable:

chmod a+x /root/bin/sync_db.bash

Configure

You probably only need to change these variables to suit your environment:

DB_USER_FROM="root"
DB_PASS_FROM="passxxx"
DB_HOST_FROM="source.example.com"
 
DB_USER_TO="root"
DB_PASS_TO="passxxx"
DB_HOST_TO="destination.example.com"

Make sure that the MySQL users have sufficient rights on both sides and you're ready to rock.

Run

Easy, make sure you've read the warning and just:

/root/bin/sync_db.bash          # or whereever you stored it

Tip

During the transfer, I wanted to make sure that no changes could be made to the active database. So: 

  • I sett up iptables to block every connection to port 3306 (MySQL), except from the receiving host.

Suggestions?

Did I overlook something? Know better ways? Got improvements?

Post a comment, I'll be happy to update the article with your proposed improvements. 

Stay up to date

You can track my blog rss articles and rss comments. You may also find my rss bookmarks interesting. Or twitter Follow me on Twitter


Like this article?

   Then Digg it!
Or use another bookmark button below to show your support &
help me spread the word.


tags: linux, mysql, disk IO, backup
category: Howto - MySQL
read: 8,323 times

Add comment

(required, shown)(required, not shown)for syntax highlighting

[CODE="Javascript"]
your_code_here();
[/CODE]

Replace "Javascript"
with "php", "text", etc.
code (to make sure you are not a spammer)

 Track replies: rss feed comments feed

Comments

#6. Kevin on 10 June 2009

Member avatar: Kevin@ Vaibhav: Obiously you can choose who the 'From' & 'To' are. So yes, these can be any host you want. Also the reverse of you initial idea.

You just have to make sure you set the right permissions so that the initiating host can access both mysql instances.

#5. Vaibhav on 10 June 2009

Gravatar.com: VaibhavIs it possible to do the reverse ?
Backup script will be run on Backup Server and pull the MySQL data from the Main Server ?

The reason being, our Backup Server is switched off most of the day. We start the backup server twice every day and run syncing script via rc.local to sync the backup server with main server and then again switch off the backup server.

... [more] I look forward to your comments.

Thx
Vai

#4. Kevin on 06 January 2009

Member avatar: Kevin@ mogie: This script does not provide means of managing permissions. They already need to be in place before you can run this.

#3. mogie on 05 January 2009

Gravatar.com: mogieI threw myself on to this, but I constantly got access denied errors of various types. I found a possible solution here:

GRANT all on *.* to 'root'@'hostname';
on booth servers with eachothers hostnames (yp..much of a mess), but it didn't seem to work out.

I then finally rather fixed my phpmyadmin login problems and exported all DBs and imported to the other server..

Any advise?

#2. Kevin on 20 October 2008

Member avatar: Kevin@ komikers: I'm somewhat missing your point, sorry. But you might want to reconsider using this script, if you feel so much doubt. It's very dangerous.

#1. komikers on 20 October 2008

Gravatar.com: komikersgreat..waht if the connection too the other mysql fail?
is it miss the data dump and start again or what happend?
and what should i change from the script. is it the echo "show DATABASE" with echo "show mydata" ?

http://komikz.blogsite.org