はじめに

個人で構築・運用している趣味サイトのインフラを AWS EC2 から Azure に移行する中で、ローカルにインストールしていた MySQL を Azure Database for MySQL(Flexible Server)に移行しました。

「マネージドDB便利そう」と軽い気持ちで始めたものの、SSL証明書の取得、phpMyAdmin ダンプの互換性対応、PDO の接続設定など、思った以上にハマりポイントが多かったので、実際に踏んだ地雷とその解決策を共有します。

対象読者

移行前後の構成

項目移行前(AWS EC2)移行後(Azure)
DBMySQL 5.7(EC2 にローカルインストール)Azure Database for MySQL Flexible Server(MySQL 8.0 互換)
接続方式localhost 接続(SSL なし)SSL 暗号化通信でリモート接続
管理・バックアップ自分で全部やるAzure が自動バックアップ・パッチ適用
アプリPHP + PDOPHP + PDO(SSL オプション追加)

環境情報

項目バージョン
移行元 MySQL5.7.27
移行先 Azure MySQL8.0(Flexible Server)
VM OSUbuntu 24.04.4 LTS
PHP8.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 failure

3 つの方法を全て試して全て失敗しました。DigiCert の CDN 側の SSL 証明書の SAN(Subject Alternative Name)が正しく設定されていないみたいです。

解決策:Ubuntu に最初から入っている証明書を使う

実は Ubuntu には DigiCert のルート証明書が最初からインストールされています。

ls /etc/ssl/certs/ | grep DigiCert
DigiCert_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.pem
AIに聞いたところ、ネット上の古い記事や過去のドキュメントで紹介されている [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 failed

cp でファイルをコピーすれば解決します。

ハマり 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  # ファイル: 644

3. 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 を使用した接続方法は、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.sql

4. 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.pem

5. 移行後にハマった運用上の問題

.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/.env

PHP から証明書が読めているかのデバッグ方法

「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.pem

DBeaver の接続設定

設定項目
Server Hostmysite-mysql.mysql.database.azure.com
Port3306
Databasetravel_map
Username<YOUR_USERNAME>

SSL タブ:

Driver Properties タブ:


Azure Database for MySQL を使ってみて

移行後は自動バックアップやパッチ適用を Azure に任せられるので、個人の運用負荷がかなり減った気がします。

一方で、SSL 証明書周りのドキュメントが実環境と乖離していたのが最大の罠でした。公式ドキュメント通りにやってもダウンロードできないので、この記事がどなたかの参考になれば幸いです。