- MySQL
mysqldumpバックアップとリストア|オプション一覧と自動化スクリプト
mysqldumpとは、MySQLのデータベースを CREATE TABLE と INSERT のSQL文として書き出す標準のバックアップツールです。 書き出したファイルを mysql コマンドに流し込めば、同じ状態に戻せます(リストア)。InnoDBなら --single-transaction を付けるだけで、サービスを止めずに一貫したバックアップが取れます。
この記事では、MySQL 8.0.46 で実際に実行して、用途別のオプションの組み合わせとダンプの中身、書き込み中にダンプしたときの一貫性(2セッションで検証)、よく出る警告・エラーの対処、gzip圧縮+世代管理のbashスクリプトとリストア後の件数照合までを結果つきで紹介します。
MySQL 8.0 は2026年4月にサポートが終了しています。この記事の手順は MySQL 8.4 LTS/9.7 でも同じコマンドで使えます。8.4 で変わった点(
mysqlpumpの削除、--master-dataから--source-dataへの置き換えなど)は「8.4/9.7 で変わったこと」にまとめました。検証は手元の 8.0 で行っています。
mysqldumpの早見表
| やりたいこと | コマンド例 |
|---|---|
| 1つのDBを丸ごと(推奨形) | mysqldump --single-transaction --routines --events app > app.sql |
CREATE DATABASE・USE も含める |
mysqldump --single-transaction --databases app > app.sql |
| 複数DB | mysqldump --single-transaction --databases app blog > two.sql |
| 全DB | mysqldump --single-transaction --all-databases --routines --events > all.sql |
| 特定のテーブルだけ | mysqldump --single-transaction app orders members > t.sql |
| テーブルを除外 | mysqldump --single-transaction --ignore-table=app.order_log app > app.sql |
| 定義(スキーマ)だけ | mysqldump --no-data --routines --events app > schema.sql |
| データだけ | mysqldump --no-create-info --skip-triggers app > data.sql |
| 条件に合う行だけ | mysqldump --no-create-info --where="ordered_at >= '2026-09-01'" app orders |
| 圧縮して保存 | mysqldump --single-transaction app | gzip > app.sql.gz |
| リストア(DBを指定) | mysql app < app.sql |
リストア(--databases 付きダンプ) |
mysql < app.sql |
| 圧縮ファイルからリストア | zcat app.sql.gz | mysql app |
| GTID有効サーバーで別環境へ移す | --set-gtid-purged=OFF を追加 |
| 権限を絞ったユーザーで取る | --no-tablespaces を追加 |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「mysqldumpバックアップとリストア|オプション一覧と自動化スクリプト」
検証環境とサンプルDB
- MySQL 8.0.46(Ubuntu 24.04 パッケージ)、
mysqldump Ver 8.0.46 - サンプルDB
app:テーブル3つ(members・orders1,000件・order_log)、ビュー1つ、関数・プロシージャ・トリガー・イベントを1つずつ
CREATE DATABASE app CHARACTER SET utf8mb4;
USE app;
CREATE TABLE members (id INT PRIMARY KEY, name VARCHAR(30), created_at DATE);
CREATE TABLE orders (id INT AUTO_INCREMENT PRIMARY KEY, member_id INT, item VARCHAR(30),
qty INT, ordered_at DATETIME, KEY (member_id));
CREATE TABLE order_log (id INT AUTO_INCREMENT PRIMARY KEY, order_id INT, logged_at DATETIME);
CREATE VIEW member_totals AS SELECT member_id, SUM(qty) AS total_qty FROM orders GROUP BY member_id;
CREATE FUNCTION tax_in(p INT) RETURNS INT DETERMINISTIC RETURN FLOOR(p * 1.1);
CREATE PROCEDURE recent_orders(IN n INT) SELECT * FROM orders ORDER BY id DESC LIMIT n;
CREATE TRIGGER trg_order_log AFTER INSERT ON orders FOR EACH ROW
INSERT INTO order_log(order_id, logged_at) VALUES (NEW.id, NOW());
CREATE EVENT ev_purge_log ON SCHEDULE EVERY 1 DAY
DO DELETE FROM order_log WHERE logged_at < NOW() - INTERVAL 30 DAY;
接続オプション(-u -p -h -P、--login-path など)は mysql コマンドと共通です。以下のコマンド例では省略しています。
用途別オプションの組み合わせと、ダンプに入るもの
同じDBを8通りのオプションでダンプし、ファイルに含まれる文を数えました。
| # | オプション | サイズ | CREATE TABLE | INSERT | トリガー | 関数・プロシージャ | イベント | CREATE DATABASE |
|---|---|---|---|---|---|---|---|---|
| 1 | (なし) app |
48,492 B | 3 | 2 | 1 | 0 | 0 | 0 |
| 2 | --single-transaction --routines --events app |
51,995 B | 3 | 2 | 1 | 2 | 1 | 0 |
| 3 | --no-data --routines --events app |
8,612 B | 3 | 0 | 1 | 2 | 1 | 0 |
| 4 | --no-create-info --skip-triggers app |
44,647 B | 0 | 2 | 0 | 0 | 0 | 0 |
| 5 | app orders members(テーブル指定) |
46,521 B | 2 | 2 | 1 | 0 | 0 | 0 |
| 6 | --no-create-info --where=... app orders |
13,552 B | 0 | 1 | 0 | 0 | 0 | 0 |
| 7 | --all-databases --routines --events |
11,114,795 B | 44 | 30 | 4 | 5 | 4 | 5 |
| 8 | --databases app |
48,737 B | 3 | 2 | 1 | 0 | 0 | 1 |
(ビューはどのDB単位のダンプにも含まれました。INSERT は orders と members の2つで、空の order_log は INSERT なしです)
表から読み取れる要点は次の3つです。
- 何も付けないと、トリガーは入るが関数・プロシージャ・イベントは入りません。 既定値が
triggers=TRUE、routines=FALSE、events=FALSEだからです(mysqldump --helpの末尾で確認できます)。DBを丸ごと戻したいときは--routines --eventsを必ず付けます。 --databasesを付けるとCREATE DATABASEとUSEが入ります。 付けないダンプは、リストア時にDB名の指定が必要です。--all-databasesにはmysqlシステムDB(ユーザーと権限)も含まれます。 サーバーごと移すとき向けで、1つのアプリのDBだけなら--databasesが扱いやすいです。
ダンプの中身を読む
--single-transaction --routines --events のダンプ(#2)の主な部分です。
-- MySQL dump 10.13 Distrib 8.0.46, for Linux (x86_64)
--
-- Host: localhost Database: app
-- ------------------------------------------------------
-- Server version 8.0.46-0ubuntu0.24.04.4
/*!50503 SET NAMES utf8mb4 */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
...
DROP TABLE IF EXISTS `orders`;
CREATE TABLE `orders` (
`id` int NOT NULL AUTO_INCREMENT,
...
) ENGINE=InnoDB AUTO_INCREMENT=1024 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
LOCK TABLES `orders` WRITE;
/*!40000 ALTER TABLE `orders` DISABLE KEYS */;
INSERT INTO `orders` VALUES (1,2,'商品1',2,'2026-09-01 00:01:00'),(2,3,'商品2',3,'2026-09-01 00:02:00'),...;
/*!40000 ALTER TABLE `orders` ENABLE KEYS */;
UNLOCK TABLES;
...
DELIMITER ;;
/*!50003 CREATE*/ /*!50017 DEFINER=`root`@`localhost`*/ /*!50003 TRIGGER `trg_order_log` AFTER INSERT ON `orders` ...
DELIMITER ;
...
-- Dumping events for database 'app'
...
-- Dumping routines for database 'app'
DELIMITER ;;
CREATE DEFINER=`root`@`localhost` FUNCTION `tax_in`(p INT) RETURNS int
...
-- Dump completed on 2026-10-02 0:27:48
| 書かれている内容 | 意味 |
|---|---|
/*!40101 ... */ |
バージョン付きコメント。MySQLは中身を実行し、他製品は無視する |
FOREIGN_KEY_CHECKS=0 |
外部キーの順番を気にせず流し込めるようにする |
DROP TABLE IF EXISTS |
既定の --add-drop-table。既存テーブルは上書きされます |
INSERT ... VALUES (...),(...) |
既定の --extended-insert。複数行を1文にまとめて高速化 |
DEFINER=root@localhost の部分 |
作成者。戻し先にそのユーザーがいないと、実行時に ERROR 1449 になる |
-- Dump completed on ... |
最後まで書けた印。自動化ではこの行の有無で成否を確かめる |
--where のダンプ(#6)には、条件がコメントで残ります。
-- WHERE: ordered_at >= '2026-09-01 12:00:00'
オプション一覧(よく使うもの)
| 分類 | オプション | 既定 | 内容 |
|---|---|---|---|
| 対象 | --databases / -B |
― | 複数DB。CREATE DATABASE・USE を含める |
| 対象 | --all-databases / -A |
― | 全DB |
| 対象 | --ignore-table=db.tbl |
― | テーブルを除外(複数回指定可) |
| 対象 | --where="条件" |
― | 条件に合う行だけ |
| 中身 | --no-data / -d |
― | 定義だけ |
| 中身 | --no-create-info / -t |
― | データだけ |
| 中身 | --routines / -R |
OFF | 関数・プロシージャ |
| 中身 | --events / -E |
OFF | イベント |
| 中身 | --triggers |
ON | トリガー(外すなら --skip-triggers) |
| 一貫性 | --single-transaction |
OFF | 1つのトランザクション内で読む(InnoDB) |
| 一貫性 | --lock-tables |
ON | DBごとに全テーブルを読み取りロック |
| 一貫性 | --lock-all-tables / -x |
OFF | 全DBをまとめてロック |
| 出力 | --add-drop-table |
ON | DROP TABLE IF EXISTS を入れる |
| 出力 | --extended-insert |
ON | 複数行INSERT(1行ずつなら --skip-extended-insert) |
| 出力 | --complete-insert |
OFF | INSERTに列名を書く(列順が違うDBへ戻すとき) |
| 出力 | --hex-blob |
OFF | BLOB・BINARY列を16進数で出す |
| 出力 | --quick |
ON | 1行ずつ読み、メモリを使いすぎない |
| 出力 | --result-file=x.sql |
― | ファイルに直接書く(Windows PowerShellの文字コード対策) |
| 複製 | --source-data=2 |
0 | バイナリログの位置をコメントで書く(8.0.26以降。旧 --master-data) |
| 複製 | --set-gtid-purged=OFF |
AUTO | GTID_PURGED の設定文を入れない |
| 権限 | --no-tablespaces |
OFF | テーブルスペース情報を出さない(PROCESS権限不要に) |
| 統計 | --column-statistics |
ON(8.0) | ヒストグラムの ANALYZE TABLE を出す |
既定で有効なものは --opt(--add-drop-table --add-locks --create-options --disable-keys --extended-insert --lock-tables --quick --set-charset)にまとまっています。 --single-transaction を付けると、--lock-tables は使われなくなります。
--single-transaction の意味を2セッションで確かめる
--single-transaction は、ダンプの最初に START TRANSACTION WITH CONSISTENT SNAPSHOT を実行し、その時点のスナップショットから全テーブルを読む仕組みです。 書き込み中でも、ダンプ開始時点の整合した状態が保存されます。
検証では、2つのテーブル stock_a・stock_b(各40万行、各行 qty=10、合計は常に 8,000,000)を用意し、別セッションで「Aから1個減らし、Bに1個足す」トランザクションを繰り返しながらダンプしました。
# mover.py:別セッションで在庫を移し続ける(合計は常に 8,000,000)
import pymysql, random, sys, time
conn = pymysql.connect(unix_socket="/tmp/t108my/mysql.sock", user="root", database="app")
end = time.time() + float(sys.argv[1]); n = 0
with conn.cursor() as cur:
while time.time() < end:
i = random.randint(1, 400000)
cur.execute("UPDATE stock_a SET qty = qty - 1 WHERE id = %s", (i,))
cur.execute("UPDATE stock_b SET qty = qty + 1 WHERE id = %s", (i,))
conn.commit(); n += 1
print("moved", n)
python3 mover.py 6 & # セッション1:6秒間書き込み続ける
sleep 1
mysqldump --skip-lock-tables app stock_a stock_b > st.sql # セッション2
# 別DBに戻して SUM(qty) の合計を確認(--single-transaction でも同じ手順)
| ダンプのオプション | ダンプ時間 | 戻したDBの合計 | 判定 |
|---|---|---|---|
--skip-lock-tables(ロックもトランザクションもなし) |
1.43秒 | 8,000,149 | 合計がずれた |
--single-transaction |
0.89秒 | 8,000,000 | 一致 |
オプションなし(既定の --lock-tables) |
1.08秒 | 8,000,000 | 一致 |
ロックもスナップショットもないと、stock_a を読み終えてから stock_b を読むまでの間に移された149個が二重に数えられました。 --single-transaction では合計がぴったり一致しています。
既定の --lock-tables でも一致しますが、こちらはダンプ中そのDBのテーブルへの書き込みを待たせる方式です。InnoDBのテーブルなら、書き込みを止めない --single-transaction が適しています。
--single-transaction で気をつけること
| 状況 | 起きること | 対応 |
|---|---|---|
| MyISAMなどトランザクション非対応のテーブル | 一貫性が保証されない | InnoDBに変える、または --lock-all-tables |
ダンプ中の ALTER TABLE・TRUNCATE・RENAME |
公式ドキュメントでは、中身がずれたりダンプが失敗したりすることがあると説明されています | DDLはバックアップの時間帯を避ける |
| 長時間のダンプ | 古いスナップショットを保つため undo ログが増える | 夜間に実行、大きいDBは MySQL Shell の dump utility も検討 |
よく出る警告・エラーと対処
PROCESS権限エラー(when trying to dump tablespaces)
バックアップ専用の、権限を絞ったユーザーで実行すると出ます。
mysqldump: Error: 'Access denied; you need (at least one of) the PROCESS privilege(s) for this operation' when trying to dump tablespaces
InnoDBだけのDBなら --no-tablespaces を付けると出なくなります。 テーブルスペース情報は、一般的なアプリのDBでは不要です。
--routines を付けたのに関数・プロシージャが入らない
SELECT, SHOW VIEW, TRIGGER, LOCK TABLES, EVENT を app.* に付けたユーザーで --routines を付けると、エラーも警告も出ずに終了コード0で、関数・プロシージャが0件のダンプができました。
-- Dumping routines for database 'app'
--
(中身なし)
MySQL 8.0.20以降は、ルーチンの定義を読むのに SHOW_ROUTINE 権限(またはグローバルな SELECT)が必要です。 付与すると2件とも出力されました。
CREATE USER 'backup'@'localhost' IDENTIFIED BY '********';
GRANT SELECT, SHOW VIEW, TRIGGER, LOCK TABLES, EVENT ON app.* TO 'backup'@'localhost';
GRANT SHOW_ROUTINE ON *.* TO 'backup'@'localhost';
| 取りたいもの | 必要な権限 |
|---|---|
| テーブルのデータ | SELECT |
| ビュー | SHOW VIEW |
| トリガー | TRIGGER |
| イベント | EVENT |
| 関数・プロシージャ | SHOW_ROUTINE(8.0.20以降) |
--single-transaction なしで取る |
LOCK TABLES |
| テーブルスペース情報 | PROCESS(--no-tablespaces なら不要) |
GTID有効サーバーの警告とリストア時の ERROR 3546
gtid_mode=ON のサーバーで1つのDBだけをダンプすると、次の警告が出ます。
Warning: A partial dump from a server that has GTIDs will by default include the GTIDs of all transactions, even those that changed suppressed parts of the database. If you don't want to restore GTIDs, pass --set-gtid-purged=OFF. To make a complete dump, pass --all-databases --triggers --routines --events.
ダンプの先頭には、GTIDの設定文が入っていました。
SET @@SESSION.SQL_LOG_BIN= 0;
SET @@GLOBAL.GTID_PURGED=/*!80000 '+'*/ '7def0173-bdab-11f1-ad0e-02fc00000001:1-2';
このダンプを、同じサーバー(GTIDが既に実行済み)の別DBへ戻すとエラーになりました。
ERROR 3546 (HY000) at line 24: @@GLOBAL.GTID_PURGED cannot be changed: the added gtid set must not overlap with @@GLOBAL.GTID_EXECUTED
| 用途 | --set-gtid-purged |
|---|---|
| 新しいレプリカを作る(GTIDを引き継ぐ) | ON(既定の AUTO でも出る) |
| 開発環境・別サーバー・同じサーバーの別DBへ戻す | OFF |
--set-gtid-purged=OFF で取り直したダンプは、GTID_PURGED の行が0件になり、警告も出ませんでした。
--column-statistics の ERROR 1109(未実行)
8.0 の mysqldump は column-statistics が既定で TRUE です。5.7 や MariaDB のサーバーに 8.0 以降の mysqldump で接続すると、Unknown table 'COLUMN_STATISTICS' in information_schema (1109) で止まることがあります。 その場合は --column-statistics=0 を付けます。この組み合わせは手元に古いサーバーがないため未実行です(--column-statistics の意味は公式ドキュメントのオプション説明で確認しています)。
リストア時のエラー
| エラー | 原因 | 対処 |
|---|---|---|
ERROR 1046 (3D000) at line 22: No database selected |
--databases なしのダンプをDB名なしで流した |
mysql app < app.sql とDB名を付ける |
ERROR 1049 (42000): Unknown database 'app_restore' |
戻し先DBがない | 先に CREATE DATABASE app_restore; |
ERROR 1449 ... The user specified as a definer does not exist(未実行) |
ビュー・ルーチンのDEFINERのユーザーが戻し先にない | 同名ユーザーを作る、または DEFINER を書き換える |
1046 と 1049 は、検証環境で実際に出たメッセージです。
自動化スクリプト:gzip圧縮+世代管理
cronで毎日動かす想定のスクリプトです。pipefail で mysqldump の失敗を検知し、gzip -t と Dump completed の行で「最後まで書けたか」を確認してから正式なファイル名にします。
まず、パスワードをコマンドラインに書かないよう、接続情報を権限600のファイルに置きます。
# /etc/mysql/backup.cnf(chmod 600)
[client]
user=backup
password=********
socket=/var/run/mysqld/mysqld.sock
#!/usr/bin/env bash
# mysql_backup.sh:mysqldump + gzip + 世代管理(MySQL 8.0 / 8.4 / 9.x 共通)
set -euo pipefail
CNF="${CNF:-/etc/mysql/backup.cnf}" # 接続情報(chmod 600)
BACKUP_DIR="${BACKUP_DIR:-/var/backups/mysql}"
DATABASES="${DATABASES:-app}" # 空白区切りで複数可
KEEP="${KEEP:-7}" # 残す世代数(DBごと)
STAMP="$(date +%Y%m%d_%H%M%S)"
mkdir -p "$BACKUP_DIR"
umask 077
trap 'rm -f -- "${tmp:-}"; echo "$(date "+%F %T") NG ${db:-?}" >&2' ERR
for db in $DATABASES; do
out="$BACKUP_DIR/${db}_${STAMP}.sql.gz"
tmp="$out.part"
start=$(date +%s)
mysqldump --defaults-extra-file="$CNF" \
--single-transaction --quick \
--routines --triggers --events \
--no-tablespaces --set-gtid-purged=OFF \
--databases "$db" | gzip -c > "$tmp"
gzip -t "$tmp" # 圧縮ファイルの破損チェック
zcat "$tmp" | tail -n 1 | grep -q 'Dump completed' # 最後まで書けたか
mv "$tmp" "$out"
echo "$(date '+%F %T') OK $db -> $out ($(du -h "$out" | cut -f1), $(( $(date +%s) - start ))s)"
# 古い世代を削除(新しい順に並べて KEEP 件より後ろ)
ls -1t "$BACKUP_DIR/${db}_"*.sql.gz | tail -n +"$((KEEP + 1))" | while read -r old; do
rm -f -- "$old"
echo "$(date '+%F %T') DEL $old"
done
done
KEEP=3 にして5回続けて実行した結果です(パスは短くしています)。
$ for i in 1 2 3 4 5; do KEEP=3 ./mysql_backup.sh; sleep 1; done
2026-10-02 00:29:54 OK app -> backups/app_20261002_002952.sql.gz (2.1M, 2s)
2026-10-02 00:29:56 OK app -> backups/app_20261002_002955.sql.gz (2.1M, 1s)
2026-10-02 00:29:58 OK app -> backups/app_20261002_002957.sql.gz (2.1M, 1s)
2026-10-02 00:30:01 OK app -> backups/app_20261002_002959.sql.gz (2.1M, 2s)
2026-10-02 00:30:01 DEL backups/app_20261002_002952.sql.gz
2026-10-02 00:30:03 OK app -> backups/app_20261002_003002.sql.gz (2.1M, 2s)
2026-10-02 00:30:04 DEL backups/app_20261002_002955.sql.gz
$ ls -l backups
-rw------- 1 root root 2107802 Oct 2 00:29 app_20261002_002957.sql.gz
-rw------- 1 root root 2107800 Oct 2 00:30 app_20261002_002959.sql.gz
-rw------- 1 root root 2107800 Oct 2 00:30 app_20261002_003002.sql.gz
4回目から古いものが削除され、常に3世代が残りました。 圧縮前43.8MB(80万行+1,000行)が2.1MBになっています。umask 077 により、ファイルは所有者だけが読める -rw------- です。
パスワードを誤った設定ファイルで動かすと、途中ファイルを消して終了コード2で止まり、既存の世代は残りました。
mysqldump: Got error: 1045: Access denied for user 'backup'@'localhost' (using password: YES) when trying to connect
2026-10-02 00:30:11 NG app
cron に登録する例です(毎日2時15分)。
15 2 * * * DATABASES="app blog" KEEP=14 /usr/local/bin/mysql_backup.sh >> /var/log/mysql_backup.log 2>&1
リストアして件数を照合する
バックアップは「戻せることを確かめて」はじめて安心できます。 最新のファイルを別名DB(app_verify)に戻し、テーブルごとの件数を元DBと比べるスクリプトです。
#!/usr/bin/env bash
# verify_restore.sh:最新のバックアップを別名DBに戻し、件数を元DBと照合する
set -euo pipefail
SRC_DB="${1:-app}"; DST_DB="${SRC_DB}_verify"
FILE="$(ls -1t "$BACKUP_DIR/${SRC_DB}_"*.sql.gz | head -n 1)"
MYSQL="mysql --defaults-extra-file=$ADMIN_CNF -N -B"
$MYSQL -e "DROP DATABASE IF EXISTS \`$DST_DB\`; CREATE DATABASE \`$DST_DB\`"
# --databases 付きダンプは USE 文を含むので、DB名を置き換えて流し込む
time (zcat "$FILE" | sed -e "s/^USE \`$SRC_DB\`;/USE \`$DST_DB\`;/" \
-e "/^CREATE DATABASE /d" | $MYSQL)
ng=0
for t in $($MYSQL -e "SELECT TABLE_NAME FROM information_schema.TABLES
WHERE TABLE_SCHEMA='$SRC_DB' AND TABLE_TYPE='BASE TABLE' ORDER BY 1"); do
a=$($MYSQL -e "SELECT COUNT(*) FROM \`$SRC_DB\`.\`$t\`")
b=$($MYSQL -e "SELECT COUNT(*) FROM \`$DST_DB\`.\`$t\`")
[ "$a" = "$b" ] && r=OK || { r=NG; ng=1; }
printf '%-10s %8s %8s %s\n' "$t" "$a" "$b" "$r"
done
exit $ng
$ BACKUP_DIR=./backups ADMIN_CNF=./admin.cnf ./verify_restore.sh app
real 0m6.734s
user 0m0.422s
sys 0m0.090s
members 4 4 OK
order_log 0 0 OK
orders 1000 1000 OK
stock_a 400000 400000 OK
stock_b 400000 400000 OK
戻した app_verify には、関数・プロシージャ2件とイベント1件も入っていました。件数に加えて、中身まで比べたいときは CHECKSUM TABLE app.orders, app_verify.orders; が使えます(検証では両方 1742228606 で一致)。
戻し先の
app_verifyにはイベントev_purge_logも作られ、スケジュールどおり動きます。検証用DBでは、確認後にDROP DATABASEするかSET GLOBAL event_scheduler=OFFの環境で行うと安心です。
8.4/9.7 で変わったこと
| 項目 | 8.0 | 8.4 LTS/9.7 |
|---|---|---|
| mysqldump の基本オプション | この記事のとおり | 同じ |
mysqlpump |
8.0.34 で非推奨(実行時に WARNING: mysqlpump is deprecated と表示) |
8.4.0 で削除。mysqldump か MySQL Shell の dump utility を使う |
| バイナリログ位置の出力 | --source-data(8.0.26〜)、--master-data は非推奨 |
--source-data を使う |
| レプリカから取る | --dump-replica(--dump-slave は非推奨) |
--dump-replica を使う |
| ダンプ内の複製用の文 | CHANGE REPLICATION SOURCE TO |
同じ。古い形式で出したいときは --output-as-version |
| ログ位置を確認するSQL | SHOW MASTER STATUS も使える |
SHOW BINARY LOG STATUS に変更(旧文は削除) |
cronやスクリプトに --master-data や mysqlpump が残っていたら、8.4へ移る前に --source-data・mysqldump に書き換えておくとスムーズです。8.0 の mysqlpump は、実行すると次の表示が出ました。
WARNING: mysqlpump is deprecated and will be removed in a future version. Use mysqldump instead.
MySQL Shell の dump utility(概要)
数十GB以上のDBでは、MySQL Shell の util.dumpInstance()/util.dumpSchemas()/util.dumpTables() と util.loadDump() が選択肢になります。公式ドキュメントでは、複数スレッドでの並列ダンプ・圧縮・進捗表示に対応すると説明されています。出力はSQL1ファイルではなくディレクトリ形式です(この記事では未実行)。
| 観点 | mysqldump | MySQL Shell dump utility |
|---|---|---|
| 出力 | SQLテキスト1ファイル | ディレクトリ(チャンク分割・圧縮) |
| 並列 | なし | あり(スレッド数を指定) |
| リストア | mysql に流し込む |
util.loadDump() |
| 向いている規模 | 数GBまでの日次バックアップ、一部のテーブル | 大きなDB、サーバー移行 |
PostgreSQL の pg_dump と比べると、mysqldump は SQLテキスト形式のみ・並列なし という違いがあります(pg_dump の使い方は別の記事で扱っています)。
よくある質問
Q. mysqldump 中にサービスは止まりますか?
A. InnoDBのテーブルで --single-transaction を付ければ、読み書きは続けられます。ダンプ中の ALTER TABLE などのDDLだけは避けます。
Q. 1つのテーブルだけ戻すことはできますか?
A. 最初から mysqldump app orders > orders.sql のようにテーブル単位で取っておくのが簡単です。DB全体のダンプから取り出す場合は、-- Table structure for table の見出しを目印に該当部分を切り出します。
Q. 文字化けを防ぐには?
A. 8.0 の mysqldump は既定で SET NAMES utf8mb4 をダンプに書きます。Windows の PowerShell で > を使うとUTF-16で保存されることがあるため、--result-file=app.sql でファイルに直接書くのがおすすめです。
Q. どのくらいの頻度・世代で取ればよいですか?
A. 「どの時点まで戻せればよいか」で決めます。1日1回のダンプなら最大1日分の更新が戻せない範囲になるため、それより細かく戻したい場合はバイナリログと組み合わせます(--source-data=2 でダンプ時点のログ位置を記録できます)。
まとめ
- 基本形は
mysqldump --single-transaction --routines --events --databases app | gzip - 既定では関数・プロシージャ・イベントは入らないので
--routines --eventsを付ける --single-transactionは書き込み中でも整合したダンプになる(検証で合計が一致、ロックなしでは149ずれた)- 権限を絞ったユーザーは
--no-tablespacesとSHOW_ROUTINE権限を用意する - GTID有効サーバーから別環境へ戻すなら
--set-gtid-purged=OFF - 自動化は
pipefail・gzip -t・Dump completedの確認・世代削除をセットに - 8.4では
mysqlpumpが削除、--master-dataは--source-dataへ。リストア検証で件数を照合しておく
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「mysqldumpバックアップとリストア|オプション一覧と自動化スクリプト」
株式会社RJCでは、データベースのバックアップと復元の手順を仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。