はじめに
個人で構築・運用している趣味サイトのインフラを AWS EC2 から Azure に移行する中で、ローカルにインストールしていた MySQL を Azure Database for MySQL(Flexible Server)に移行しました。
「マネージドDB便利そう」と軽い気持ちで始めたものの、SSL証明書の取得、phpMyAdmin ダンプの互換性対応、PDO の接続設定など、思った以上にハマりポイントが多かったので、実際に踏んだ地雷とその解決策を共有します。
対象読者
- AWS EC2やAzure VM などで MySQL をローカル運用していて、Azure のマネージドDB に移行したい人
- PHP(PDO)+ MySQL の構成で Azure Database for MySQL に接続したい人
- Azure 特有の SSL 接続周りで困っている人
移行前後の構成
| 項目 | 移行前(AWS EC2) | 移行後(Azure) |
|---|---|---|
| DB | MySQL 5.7(EC2 にローカルインストール) | Azure Database for MySQL Flexible Server(MySQL 8.0 互換) |
| 接続方式 | localhost 接続(SSL なし) | SSL 暗号化通信でリモート接続 |
| 管理・バックアップ | 自分で全部やる | Azure が自動バックアップ・パッチ適用 |
| アプリ | PHP + PDO | PHP + PDO(SSL オプション追加) |
環境情報
| 項目 | バージョン |
|---|---|
| 移行元 MySQL | 5.7.27 |
| 移行先 Azure MySQL | 8.0(Flexible Server) |
| VM OS | Ubuntu 24.04.4 LTS |
| PHP | 8.3.6 |
| Web サーバー | Apache 2 |
| 記事執筆時期 | 2026年7月 |
1. phpMyAdmin のダンプを Azure 向けに修正する
phpMyAdmin からエクスポートした SQL ダンプは、そのまま Azure Database for MySQL に流し込むとエラーになります。今回必要だった修正は主に 3 つでした。
修正①:CREATE DATABASE / USE 文の追加
phpMyAdmin のダンプにはデータベースの作成文が含まれていないことがあります。Azure 側では当然データベースが存在しないので、ファイルの先頭に追加します。
CREATE DATABASE IF NOT EXISTS `travel_map` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE `travel_map`;ちなみに、元のデータベース名は lb37c_travel_map というホスティングサービスが自動で付けた名前だったので、この機会に travel_map というわかりやすい名前に変更しました。
修正②:インデックス定義のインライン化(MySQL 8.0 互換)
phpMyAdmin が吐き出すダンプは、テーブル作成と PRIMARY KEY / AUTO_INCREMENT の定義が別々のステートメントに分かれています。
-- phpMyAdmin 形式(MySQL 5.7 向け)
CREATE TABLE `photos` (
`id` int(10) UNSIGNED NOT NULL COMMENT '写真ID',
...
);
ALTER TABLE `photos` ADD PRIMARY KEY (`id`);
ALTER TABLE `photos` MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT;Azure Database for MySQL(MySQL 8.0)ではこの形式でもエラーにはならないことが多いですが、CREATE TABLE の中にインラインで定義する方が確実に動作します。
-- Azure 向け(インライン定義)
CREATE TABLE IF NOT EXISTS `photos` (
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '写真ID',
...
PRIMARY KEY (`id`)
);修正③:データ内のエスケープ漏れ
INSERT 文のテキストデータにシングルクォートが含まれている場合にエスケープ漏れがあるとインポートが止まります。phpMyAdmin が自動でエスケープしてくれることが多いですが、手動でダンプを編集した場合は要注意です。
- 'I couldn't help but take a photo.'
+ 'I couldn\'t help but take a photo.'2. SSL 証明書の準備で 3 回ハマった話
Azure Database for MySQL は SSL 接続が必須(require_secure_transport = ON)です。接続するには CA 証明書が必要になりますが、ここで一番時間を使いました。
ハマり 1:DigiCert の公式 URL からダウンロードできない
Microsoft の公式ドキュメント(TLS/SSL を使用した暗号化された接続 - Azure Database for MySQL)には「以下の URL から CA 証明書をダウンロードしてください」と書いてありますが上手くいきませんでした…(なんでや!)(2026年6月時点)
2026年7月:現在は更新されていました。
wget <https://dl.cacerts.digicert.com/DigiCertGlobalRootCA.crt.pem>
# → ERROR: no certificate subject alternative name matches
wget --no-check-certificate <https://dl.cacerts.digicert.com/DigiCertGlobalRootCA.crt.pem>
# → ERROR 400: Bad Request
curl -o DigiCertGlobalRootCA.crt.pem <https://dl.cacerts.digicert.com/DigiCertGlobalRootCA.crt.pem>
# → curl: (35) sslv3 alert handshake failure3 つの方法を全て試して全て失敗しました。DigiCert の CDN 側の SSL 証明書の SAN(Subject Alternative Name)が正しく設定されていないみたいです。
解決策:Ubuntu に最初から入っている証明書を使う
実は Ubuntu には DigiCert のルート証明書が最初からインストールされています。
ls /etc/ssl/certs/ | grep DigiCertDigiCert_Global_Root_G2.pem ← これが使える
DigiCert_Global_Root_G3.pem
DigiCert_TLS_ECC_P384_Root_G5.pem
...注意点: Azure Database for MySQL Flexible Server が使用しているのは DigiCert Global Root G2 です。DigiCert_Global_Root_CA.pem(G2 なし)ではないので間違えないように。
sudo mkdir -p /var/www/html/certs
sudo cp /etc/ssl/certs/DigiCert_Global_Root_G2.pem /var/www/html/certs/DigiCertGlobalRootCA.crt.pemAIに聞いたところ、ネット上の古い記事や過去のドキュメントで紹介されている[https://dl.cacerts.digicert.com/](https://dl.cacerts.digicert.com/)...というURLは、DigiCert側のCDNの変更により現在はSSLハンドシェイクエラーや400エラーになります。現在の正しいドメインはdl.のない[https://cacerts.digicert.com/](https://cacerts.digicert.com/)...です。また、Azure側で「SHA-1(古い規格)」のルート証明書(G1)から「SHA-256」の「G2証明書」への移行が進んでいるため、今回のハマりが生まれてしまったっぽい…
ハマり 2:シンボリックリンクだと SSL 接続エラーになる
最初は ln -s で済ませようとしましたが、mysql クライアントが正しく読めませんでした。
# これだとエラーになる
sudo ln -s /etc/ssl/certs/DigiCert_Global_Root_G2.pem /var/www/html/certs/DigiCertGlobalRootCA.crt.pem
mysql -h xxx.mysql.database.azure.com -u user -p --ssl-ca=/var/www/html/certs/DigiCertGlobalRootCA.crt.pem
# → ERROR 2026 (HY000): SSL connection error: SSL_CTX_set_default_verify_paths failedcp でファイルをコピーすれば解決します。
ハマり 3:ディレクトリの実行権限が不足
証明書ファイルのパーミッション設定時に chmod -R 600 をかけてしまい、ディレクトリの実行権限(x)まで消えてしまったケースがありました。
# certs/ ディレクトリの権限が drw------- になっている
# → PHP の file_exists() が false を返す
# → SSL なしで接続しようとして require_secure_transport=ON に弾かれる
# 正しいパーミッション
sudo chmod 755 /var/www/html/certs/ # ディレクトリ: 755
sudo chmod 644 /var/www/html/certs/*.pem # ファイル: 6443. SQL インポートでも -ssl-mode=REQUIRED を使う
証明書の準備ができても、mysql CLI での接続でまたハマりました。
-ssl-ca 指定でエラー
mysql -h mysite-mysql.mysql.database.azure.com -u <YOUR_USERNAME> -p \
--ssl-ca=/var/www/html/certs/DigiCertGlobalRootCA.crt.pem \
< dump.sql
# → ERROR 2026 (HY000): SSL connection error: SSL_CTX_set_default_verify_paths failed-ssl-mode=REQUIRED で成功
mysql -h mysite-mysql.mysql.database.azure.com -u <YOUR_USERNAME> -p \
--ssl-mode=REQUIRED \
< dump.sql-ssl-mode=REQUIREDは「SSL 暗号化は必須だが、CA 証明書の厳密な検証はスキップ」するオプションです。通信自体は暗号化されるのでセキュリティ上の問題はないと思われます。
この --ssl-mode=REQUIRED を使用した接続方法は、Microsoftの公式ドキュメント(TLS/SSL を使用した暗号化された接続 - Azure Database for MySQL)の「Connect using mysql command-line client with TLS/SSL」セクションでも、標準的な接続用オプションとして紹介されています。再インポート時の Duplicate entry エラー
一度インポートに失敗した後に再度実行すると Duplicate entry 'X' for key 'photos.PRIMARY' が出ます。テーブルを一度 DROP してからやり直すと上手くいきます。
mysql -h mysite-mysql.mysql.database.azure.com -u <YOUR_USERNAME> -p \
--ssl-mode=REQUIRED \
-e "USE travel_map; DROP TABLE IF EXISTS photos; DROP TABLE IF EXISTS users;"
# 再インポート
mysql -h mysite-mysql.mysql.database.azure.com -u <YOUR_USERNAME> -p \
--ssl-mode=REQUIRED \
< lb37c_travel_map_azure.sql4. PHP(PDO)からの SSL 接続設定
アプリケーション側も SSL 接続に対応させる必要があります。
db_connect.php の実装
<?php
require_once __DIR__ . '/vendor/autoload.php';
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();
$host = $_ENV['DB_HOST'];
$db = $_ENV['DB_NAME'];
$user = $_ENV['DB_USER'];
$pass = $_ENV['DB_PASS'];
$dsn = "mysql:host=$host;dbname=$db;charset=utf8mb4";
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
];
// Azure Database for MySQL はSSL接続が必須
$sslCa = $_ENV['DB_SSL_CA'] ?? '';
if (!empty($sslCa) && file_exists($sslCa)) {
$options[PDO::MYSQL_ATTR_SSL_CA] = $sslCa;
$options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] = false;
}
try {
$pdo = new PDO($dsn, $user, $pass, $options);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
exit;
}MYSQL_ATTR_SSL_VERIFY_SERVER_CERT = false は大丈夫なのか?
mysql CLI の --ssl-mode=REQUIRED と同じ動作です。SSL 暗号化自体は有効で、CA 証明書の厳密な検証(ホスト名の一致確認等)だけをスキップしています。
これを true のままにすると、先ほどのシンボリックリンク問題や OpenSSL のパス問題と同じエラーが PHP 側でも発生します。
.env の設定例
DB_HOST=mysite-mysql.mysql.database.azure.com
DB_NAME=travel_map
DB_USER=<YOUR_USERNAME>
DB_PASS=<your_password>
DB_SSL_CA=/var/www/html/certs/DigiCertGlobalRootCA.crt.pem5. 移行後にハマった運用上の問題
.env のパーミッション問題(一番ハマった)
VM 上で sudo nano /var/www/html/.env でファイルを編集すると、ファイルの所有者が www-data から azureuser(または root)に変わってしまうことがあります。
すると Apache(www-data ユーザー)が .env を読めなくなり、ページが真っ白になる(PHP Fatal Error)か、DB 接続エラーになります。
# Apache のエラーログで確認
sudo tail -20 /var/log/apache2/error.log
# → PHP Fatal error: Unable to read any of the environment file(s) at [/var/www/html/.env]
# 修正
sudo chown www-data:www-data /var/www/html/.env
sudo chmod 600 /var/www/html/.env予防策: VM 上でファイルを編集したら、以下のコマンドで権限をまとめてリセットする癖をつけましょう。
sudo chown -R www-data:www-data /var/www/html/
sudo chmod -R 755 /var/www/html/
sudo chmod 600 /var/www/html/.envPHP から証明書が読めているかのデバッグ方法
「DB に繋がらない」とき、SSL 証明書の問題なのか .env の問題なのかを切り分けるには、以下のワンライナーが便利です。
sudo -u www-data php -r "
require_once '/var/www/html/vendor/autoload.php';
\$dotenv = Dotenv\Dotenv::createImmutable('/var/www/html');
\$dotenv->load();
echo 'DB_SSL_CA = ' . (\$_ENV['DB_SSL_CA'] ?? 'NOT SET') . PHP_EOL;
\$ca = \$_ENV['DB_SSL_CA'] ?? '';
echo 'file_exists = ' . (file_exists(\$ca) ? 'YES' : 'NO') . PHP_EOL;
echo 'is_readable = ' . (is_readable(\$ca) ? 'YES' : 'NO') . PHP_EOL;
"file_exists = NO が返ったら、証明書ファイルのパスかディレクトリのパーミッションを見直してください。
6. DBeaver から Azure DB に接続する@MacOS
ローカルの Mac から GUI で Azure DB の中身をするためにDBeaverを利用しました。ただし、ここにもハマりポイントがありました。
Azure 側のファイアウォール設定
Azure Portal → MySQL フレキシブル サーバー →「ネットワーク」→「+ 現在のクライアント IP アドレスを追加」で、自分の Mac のIPからのアクセスを許可する必要があります。
SSL 証明書の問題(Mac でも DigiCert からダウンロードできない)
VM と同様に curl でダウンロードしようとしても失敗します。VM から scp でコピーするのが確実です。
scp -i ~/.ssh/Mysite_key.pem azureuser@<vm-ip>:/etc/ssl/certs/DigiCert_Global_Root_G2.pem ~/Downloads/AzureMySQL_CA.pemDBeaver の接続設定
| 設定項目 | 値 |
|---|---|
| Server Host | mysite-mysql.mysql.database.azure.com |
| Port | 3306 |
| Database | travel_map |
| Username | <YOUR_USERNAME> |
SSL タブ:
- Require SSL: ✅
- Verify server certificate: ☐(チェックを外す)
- CA certificate:
~/Downloads/AzureMySQL_CA.pem
Driver Properties タブ:
allowPublicKeyRetrieval=true
Azure Database for MySQL を使ってみて
移行後は自動バックアップやパッチ適用を Azure に任せられるので、個人の運用負荷がかなり減った気がします。
一方で、SSL 証明書周りのドキュメントが実環境と乖離していたのが最大の罠でした。公式ドキュメント通りにやってもダウンロードできないので、この記事がどなたかの参考になれば幸いです。