背景レポートツール用に大きなテーブルをCSVファイルにエクスポートするデータ移行作業を行っていました。標準的な SELECT ... INTO OUTFILE コマンドを実行し、すぐに結果が得られると思っていましたが、MySQLのセキュリティエラーによって即座にブロックされました。このエラーは、LOAD DATA INFILE を使用してデータを一括ロードしようとする際にも頻繁に発生します。
mysql> SELECT * FROM orders INTO OUTFILE '/tmp/orders_dump.csv';
ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement
このエラーはバグではなく、セキュリティ機能です。MySQLは secure-file-priv 変数を使用して、サーバーがファイルを読み書きできる場所を制限しています。これにより、SQLインジェクション攻撃を受けた場合でも、攻撃者が機密性の高いシステムファイル(/etc/passwd など)を読み取ったり、Webルートに悪意のあるスクリプトを書き込んだりするのを防ぎます。
デバッグ手順まず最初に行うべきことは、サーバーがどのように制限されているかを正確に把握することです。MySQLシェルから直接 secure_file_priv 変数の現在の値を確認できます。
mysql> SHOW VARIABLES LIKE "secure_file_priv";
+------------------+-----------------------+
| Variable_name | Value |
+------------------+-----------------------+
| secure_file_priv | /var/lib/mysql-files/ |
+------------------+-----------------------+
1 row in set (0.01 sec)
出力結果の解釈- 特定のパス(例: /var/lib/mysql-files/): サーバーはこの特定のディレクトリ内でのみインポート/エクスポート操作を許可します。- NULL: サーバーはすべてのインポートおよびエクスポート操作を無効にしています。これは、新しいMySQLのインストール時のデフォルト設定として一般的です。- 空の値 (""): 制限はありません。これは安全ではありませんが、mysql ユーザーがOSレベルの権限を持つ場所であればどこでも読み書きが可能です。## 解決策### 方法 1: 許可されたディレクトリを使用する(推奨)変数に特定のパスが設定されている場合、最も簡単で安全な修正方法は、単にファイルをそこに移動することです。/tmp/ に書き込もうとするのではなく、指定された安全なフォルダを使用してください。
-- secure_file_priv が /var/lib/mysql-files/ の場合に動作します
SELECT * FROM orders
INTO OUTFILE '/var/lib/mysql-files/orders_dump.csv'
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n';
エクスポート後、コマンドラインを使用してそのディレクトリから目的の保存先にファイルを移動できます。
方法 2: 設定を変更する(永続的な修正)別の場所にファイルをエクスポートする必要がある場合、または現在の値が NULL の場合は、MySQLの設定ファイルを変更する必要があります。
Linux (Ubuntu/Debian/CentOS) の場合1. MySQLの設定ファイル(通常は my.cnf または mysqld.cnf)を開きます。
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
# または
sudo nano /etc/my.cnf
[mysqld]セクションを探し、secure-file-privのエントリを見つけます。存在しない場合は追加してください。制限を完全に無効にするには、空の文字列を設定します。
[mysqld]
secure-file-priv = ""
- ファイルを保存し、MySQLサービスを再起動します。
sudo systemctl restart mysql
Windows の場合1. my.ini ファイルの場所を確認します(通常は C:\ProgramData\MySQL\MySQL Server X.X\ にあります)。なお、ProgramData は隠しフォルダであることに注意してください。
secure-file-privの行を探して変更します。
secure-file-priv=""
services.mscを使用して MySQL サービスを再起動します。
方法 3: AppArmor への対処(Ubuntu 特有)secure-file-priv = "" を設定しても、Ubuntu の AppArmor セキュリティモジュールが特定のディレクトリへの書き込み操作をブロックし続ける場合があります。設定を変更したにもかかわらず "Permission denied" エラーが表示される場合は、AppArmor プロファイルを編集する必要があります。
sudo nano /etc/apparmor.d/usr.sbin.mysqld
許可したいパス(例: /data/)を追加します。
/data/ r,
/data/** rw,
その後、AppArmor をリロードします。
sudo systemctl reload apparmor
確認手順修正が機能したことを確認するには、MySQLに再度ログインして変数を再確認します。
mysql> SHOW VARIABLES LIKE "secure_file_priv";
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| secure_file_priv | |
+------------------+-------+
値が空であれば、小さなテストエクスポートを試してみてください。
mysql> SELECT 1 INTO OUTFILE '/tmp/test_write.txt';
Query OK, 1 row affected (0.00 sec)
/tmp/ にファイルが正常に作成されれば、問題は解決です。

