10.

Django MySQL 接続エラー 2006 / 2003 / 1045 の原因と対処を整理

編集
この記事の要点
  • 2003 = サーバーに到達できない(プロセス停止 / FW / ポート違い)
  • 2006 = いったん繋がるが切れる(wait_timeout / max_allowed_packet / プロセス再起動)
  • 1045 = 認証失敗(user / password / host が誤り)
  • 最初にやること: mysql -h HOST -u USER -p で Django 外から接続確認
  • Django 側は settings.pyDATABASESCONN_MAX_AGE を見直す
  • 長時間稼働でも切れない設定は CONN_HEALTH_CHECKS = True(Django 4.1+)

エラーの種類別 早見表

エラーコード意味主な原因
(2003) Can't connect to MySQL server on 'host' (111)そもそも到達できないMySQL 停止 / FW / bind-address / ポート違い
(2006) MySQL server has gone away接続が切れたwait_timeout / max_allowed_packet 超過 / MySQL 再起動
(2013) Lost connection to MySQL server during queryクエリ実行中に切れたネットワーク不安定 / 巨大クエリ / OOM kill
(1045) Access denied for user認証失敗user / password / host 不一致
(1049) Unknown databaseデータベースが存在しないNAME のスペルミス or 未作成

切り分け1: Django の外から接続できるか

# Django サーバが動いているマシンから実行
mysql -h 192.168.1.10 -P 3306 -u myuser -p mydb

# パスワード入力後にプロンプトが出れば OK
mysql>

# ここで失敗する場合は MySQL 側の問題 → Django 設定ではない

原因A: MySQL が起動していない

# 状態確認
sudo systemctl status mysql       # Ubuntu / Debian
sudo systemctl status mysqld      # RHEL / CentOS

# 起動
sudo systemctl start mysql

# 起動時自動起動
sudo systemctl enable mysql

# ポートが Listen しているか
sudo ss -tlnp | grep 3306
# LISTEN 0 151 127.0.0.1:3306 ...

原因B: bind-address が 127.0.0.1 のみ

外部マシンの Django から接続したい場合、MySQL がローカルしか受け付けていないと 2003 になります:

# /etc/mysql/mysql.conf.d/mysqld.cnf (Ubuntu)
# /etc/my.cnf.d/server.cnf (RHEL)

[mysqld]
# 外部接続を許可する場合
bind-address = 0.0.0.0
# IPv4 のみ
# bind-address = *
port = 3306
sudo systemctl restart mysql

# ユーザーにも外部 host からのアクセス権を付与
mysql -u root -p
mysql> CREATE USER 'myuser'@'%' IDENTIFIED BY 'mypass';
mysql> GRANT ALL ON mydb.* TO 'myuser'@'%';
mysql> FLUSH PRIVILEGES;

原因C: ファイアウォール

# Ubuntu (ufw)
sudo ufw allow 3306/tcp
sudo ufw status

# RHEL (firewalld)
sudo firewall-cmd --permanent --add-port=3306/tcp
sudo firewall-cmd --reload

# AWS EC2 → Security Group で 3306 を許可
# RDS なら DB の Security Group に EC2 の Security Group を inbound に追加

原因D: socket vs TCP の食い違い

Django から HOST を空文字 / localhost にすると、Linux ではソケットファイル経由になり、ファイルパスが合わないと 2002 / 2003 になります:

# 確実に TCP で接続させる
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'mydb',
        'USER': 'myuser',
        'PASSWORD': 'mypass',
        'HOST': '127.0.0.1',   # localhost ではなく 127.0.0.1
        'PORT': '3306',
    }
}

# ソケット接続する場合
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'OPTIONS': {
            'unix_socket': '/var/run/mysqld/mysqld.sock',
        },
        ...
    }
}

原因E: 2006 / wait_timeout で切れる

「長時間放置した Django プロセスが、最初のリクエストで 2006 を吐く」典型パターン:

-- 現在の設定確認
SHOW VARIABLES LIKE 'wait_timeout';
-- wait_timeout 28800 (8時間)

SHOW VARIABLES LIKE 'max_allowed_packet';
-- max_allowed_packet 16777216 (16MB)

-- 大きく取りたい場合(my.cnf)
[mysqld]
wait_timeout = 86400
max_allowed_packet = 64M

Django 側でも対応:

DATABASES = {
    'default': {
        ...
        # コネクションプール: 60 秒で再接続
        'CONN_MAX_AGE': 60,
        # Django 4.1+: クエリ前に ping して死んでいたら再接続
        'CONN_HEALTH_CHECKS': True,
    }
}

原因F: 1045 認証失敗

-- MySQL 側でユーザー存在確認
SELECT user, host, plugin FROM mysql.user WHERE user = 'myuser';

-- パスワードを設定し直す
ALTER USER 'myuser'@'%' IDENTIFIED BY 'newpassword';

-- caching_sha2_password 認証に変更(MySQL 8 default)
ALTER USER 'myuser'@'%' IDENTIFIED WITH caching_sha2_password BY 'newpassword';

-- 古い mysql_native_password が必要なら
ALTER USER 'myuser'@'%' IDENTIFIED WITH mysql_native_password BY 'newpassword';

FLUSH PRIVILEGES;

診断ワンライナー

# Django shell から接続確認
python manage.py shell -c "from django.db import connection; connection.ensure_connection(); print('OK')"

# 設定値ダンプ
python manage.py shell -c "from django.conf import settings; print(settings.DATABASES)"

# RAW 接続テスト
python -c "import MySQLdb; c = MySQLdb.connect(host='127.0.0.1', user='myuser', passwd='mypass', db='mydb'); print(c)"

FAQ

Q: 開発環境では動くのに本番だけ 2003
A: 9 割はセキュリティグループ / ファイアウォール。本番 DB の Security Group に EC2 / ECS のセキュリティグループを inbound 3306 で追加。

Q: gunicorn worker 数を増やしたら 2006 が頻発
A: max_connections 超過の可能性。SHOW STATUS LIKE 'Threads_connected' を確認し、CONN_MAX_AGE を下げる or PgBouncer / ProxySQL 導入。

Q: docker-compose で 2003
A: HOST: 'db'(サービス名)にする。localhost127.0.0.1 は同コンテナ内を指してしまう。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. Invalid HTTP_HOST header: '...'. You may need to add '...' to ALLOWED_HOSTS
  2. CommandError: You must set settings.ALLOWED_HOSTS if DEBUG is False.
  3. django.utils.datastructures.MultiValueDictKeyError
  4. Forbidden (403) CSRF verification failed. Request aborted.
  5. ModuleNotFoundError: No module named 'MySQLdb'
  6. WARNINGS: ?: (mysql.W002) MySQL Strict Mode is not set for database connection
  7. Unknown column 'table_name.id' in 'field list'
  8. RuntimeError: Model class ~ doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.
  9. get() returned more than one MynumberRegist -- it returned 2!
  10. django.db.utils.OperationalError: (2006, "Can't connect to MySQL server")
  11. 'include' is not defined