It's hardly worth writing about how important it is to regularly back up important data. Just visit internet forums, which are full of posts about the loss of ultra-important data. For beginner users, backup is associated with copying files/directories from one place to another, often forgetting about a database backup. Since MySQL is currently the most popular database, I'll try to cover the basics of making backups.
There are several ways to make a MySQL database backup; the choice of method depends on the storage engine used.
When using the MyISAM engine, we have several methods to choose from. The first is copying files, the second is using the mysqldump tool. However, if we use the InnoDB engine, which has been the default since MySQL 5.5, it's better not to risk copying files. We can also use mysqldump or the very good Percona XtraBackup application.
The simplest and most universal method, independent of the engine used by the database, is mysqldump. The matter gets a bit more complicated when there's a large amount of data to archive. Dumping data to SQL format for a (MyISAM) database of 3.3 GB took ~14 min on a lightly loaded machine (CPU: ATOM N2800 2 cores/2 threads, 2 x 500 GB RAID 0/1 disk), but restoring it took ~70 min.
I'll focus on the binary method (copying files) and on the mysqldump tool.
As I mentioned earlier, the basic criterion for choosing a backup method is the database engine. We can check this in several ways, e.g:
# mysqlshow -u userName --status database_name -p
Enter password:
Database: mysql
+---------------------------+--------+---------+------------+------+----------------+-------------+--------------------+--------------+-----------+----------------+---------------------+---------------------+---------------------+-------------------+----------+----------------+---------------------------------------------------+
| Name | Engine | Version | Row_format | Rows | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Create_time | Update_time | Check_time | Collation | Checksum | Create_options | Comment |
+---------------------------+--------+---------+------------+------+----------------+-------------+--------------------+--------------+-----------+----------------+---------------------+---------------------+---------------------+-------------------+----------+----------------+---------------------------------------------------+
| columns_priv | MyISAM | 10 | Fixed | 0 | 0 | 0 | 227994731135631359 | 4096 | 0 | | 2013-04-23 00:34:12 | 2013-04-23 00:34:12 |
Knowing the database engine now, we can move on to action.
Binary method ( MyISAM ONLY !!! )
- machine_1
- We locate where the database files are with the command: grep datadir /etc/mysql/my.cnf (Debian) or grep datadir /etc/my.cnf (Red Hat/Fedora/Centos); I'm assuming the standard Debian location /var/lib/mysql
- We block writing data to tables in two ways:
- By issuing a command in the MySQL console: FLUSH TABLES WITH READ LOCK;
- By shutting down the MySQL server: /etc/init.d/mysql stop
- We copy the database we're interested in: cp -R /var/lib/mysql/database_name /home/backup
- If we used the FLUSH TABLES... command, we now need to remove the lock by logging into the MySQL console and issuing the command UNLOCK TABLES;
- All that's left is to copy the database directory to the other machine: scp -r /home/backup/database_name user@machine_2:/home/user
- machine_2
- We copy the database directory into the directory where database directories are stored: cp -R /home/user/added_database /var/lib/mysql
- Now we can check that MySQL already sees the added database:
# mysql -u user -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 36
Server version: 5.xxx
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| added_database |
+--------------------+
3 rows in set (0.00 sec)
mysql> use added_database
Database changed
mysql> show tables;
ERROR 1018 (HY000): Can't read dir of './added_database/' (errno: 13)
The mysqldump tool
This is without doubt probably the most popular method of backing up a MySQL database. Mysqldump dumps data into SQL or XML format. First, a few options:
| Option | Meaning |
|---|---|
| -u username | username |
| -p password | user password |
| -h IP address/domain name | address of the remote server |
| --port=port number | the remote server's listening port, if different from 3306 |
| --databases db1 db2... | dump several databases at once |
| --all-databases | dump all databases |
| --no-data | dump the database structure only, skipping the data |
| --no-create-info | dump only the data, without the structure (tables, fields, indexes...) |
| --ignore-table=table_name | skip the specified table during the dump |
| --add-drop-database | restore the database while dropping the existing one |
| --add-drop-table | restore the table while dropping the existing one |
| --default-character-set=utf8 | default character encoding |
| --xml | dump the database in xml format |
The output of the mysqldump tool is sent to standard output, i.e. usually the screen, so we'll redirect the entire stream to a file (e.g. command > file.out). REMEMBER TO CHECK THE USER HAS THE APPROPRIATE DATABASE PERMISSIONS! We don't need to use a space after either the -u or -p option. When creating a backup from the console, we don't need to provide the password - the application will ask for it itself, so it won't be saved in the history. We only need to provide the password when we use mysqldump in a script.
...and finally a few examples:
| Command | Meaning |
|---|---|
| dump a local database | mysqldump -uuserName -p db_name > db_name.sql |
| dump local databases | mysqldump -uuserName -p --databases db_1 db_2 db_3 > databases.sql |
| dump all local databases | mysqldump -uuserName -p --all-databases > all_databases.sql |
| dump selected tables | mysqldump -uuserName -p db_name table_name_1 table_name_2 > db_name.sql |
| dump a database excluding specified tables (table name preceded by the database name!) | mysqldump -uuserName -p -ignore-table db_name.table_name > db_name.sql |
| a copy of just the database structure, without data | mysqldump -uuserName -p --no-data database_name > database_name.sql |
| dump a database in xml format, utf-8 encoding | mysqldump -uuserName -p --default-character-set=utf8 --xml database_name > db_name.xml |
| dump and compress a database (very effective for large databases) | mysqldump -uuserName -p db_name | gzip > db_name.gz |
| dump a database while simultaneously copying the file to a remote server | mysqldump -uuserName -p db_name | ssh userName@remote_host 'cat > /path/db_name.sql' |
| dump a database from a remote host | mysqldump -h ip/remote_machine_domain -uuserName -p db_name > db_name.sql |
Backing up a database to a remote machine along with an update
Often, external access to the MySQL server is blocked. In that case the last example above won't work. This can easily be worked around using ssh. At least an empty database must already exist on the remote server.
mysqldump -uroot -p password db_name | ssh userName@remote_host mysql -uuserName -p password db_name
Restoring a MySQL database backup
Restoring a database isn't complicated: mysql -uuserName db_name < db_name.sql -p, where the database must already exist.