DjangoからMySQL/MariaDBへ接続するには、使うPython環境・driver・DB aliasと有効設定を確認します。接続確認と、migrateによるschema変更は別作業です。この記事の新しい例はDjango5.2.18/mysqlclient2.2.7/MySQL8.4.13の隔離検体で確認しています。
実行環境とdriverを先に確認する
同じpythonコマンド名でも、venv/実行プロセスによって導入済みdriverは異なります。Djangoの組込みMySQLバックエンドにはmysqlclient用のadapterがあります。MySQL Connector/Pythonは別adapterの対応条件を確認します。PyMySQLのinstall_as_MySQLdb()があるだけで全Django版/認証/型/TLSまで互換と判断せず、バージョン情報を偽って要件検査を回避しません。今回はPyMySQLを追加導入/実行していません。
明示した環境変数からローカル検体へ設定する例
次は既にある検体DB/専用ユーザーへ接続するための部分設定です。完全な本番settings.pyではなく、既存プロジェクト全体を置換しません。DB_NAME/DB_USER/DB_PASSWORD/DB_HOST/DB_PORTを対象環境で明示し、実パスワードをソースへ書きません。変数がない場合に偶然別DBへ接続しないよう、既定host等へフォールバックしない例です。環境変数に置くだけで秘密の保護が完成するわけではありません。
import os
# Local connection probe only, not a complete production settings/TLS policy.
# Use the intended environment; do not put real credentials in public source.
DATABASES = {
"default": {
"ENGINE": "django.db.backends.mysql",
"NAME": os.environ["DB_NAME"],
"USER": os.environ["DB_USER"],
"PASSWORD": os.environ["DB_PASSWORD"],
"HOST": os.environ["DB_HOST"],
"PORT": os.environ["DB_PORT"],
"CONN_MAX_AGE": 0,
"OPTIONS": {"charset": "utf8mb4", "connect_timeout": 5},
}
}
OPTIONSは別の接続値を上書きし得ます。read_default_fileや別aliasもあるため、settingsのNAME等だけで実接続先を決めつけません。charset=utf8mb4は接続の文字コードで、既存表/列の文字コードや照合順序を変更しません。sql_modeを単一値へ上書きして他の規則を落とさず、既存値/要件を確認します。
migrateせずに接続を調べる
許可されたDjango shell等で次の関数を定義し、print(probe_connection())を実行する例です。default以外を確認する場合は承認済みのaliasを明示します。DB名・認証アカウント・版・sql_modeを読み、例外の生メッセージやパスワードは出しません。出力のhost/user等もそのまま公開しません。
from django.db import DatabaseError, connections
def probe_connection(alias="default"):
# Authorized management context only; do not publish host/user metadata.
connection = connections[alias]
if connection.vendor != "mysql":
raise ValueError("Select the intended MySQL/MariaDB alias")
params = connection.get_connection_params()
result = {
"alias": alias,
"host": params.get("host"),
"port": params.get("port"),
"database": params.get("database"),
"username": params.get("user"),
"password_configured": bool(params.get("password")),
}
try:
with connection.cursor() as cursor:
cursor.execute(
"SELECT VERSION(), DATABASE(), CURRENT_USER(), @@SESSION.sql_mode"
)
version, database, account, mode = cursor.fetchone()
result.update(ok=True, server_version=version, database_name=database,
authenticated_account=account, sql_mode=mode)
except DatabaseError as error:
# Do not expose SQL, full driver messages, URLs or credentials.
result.update(ok=False, exception=type(error).__name__,
mysql_code=error.args[0] if error.args else None)
finally:
connection.close()
return result
この関数は明示したaliasのcursorを使い、実ORMのルーター全経路やレプリカの整合性を確認しません。読取成功と、業務処理/書込/マイグレーションの権限は別です。新しい検体ではSELECTが成功してもINSERT/CREATE TABLEは拒否され、表・データ・権限の前後不変を確認しました。
認証・接続・設定SQLの失敗を区別する
1045の認証失敗を、表への操作権限不足やDB名不一致と混同しません。2002等も番号だけで全原因を決めず、実際のメッセージ・ホスト/ソケット/ポートを確認します。Unknown databaseを見て新DBを自動作成しません。旧本番例のSET sql_mode=..., NAMES ...はこの検体では受理され、カンマがあるだけで構文エラーとは扱いません。一方、存在しない変数を使う検体のinit_commandは1193で失敗しました。設定SQLの失敗を認証失敗と即断せず、実際の命令と対象版を確認します。
本番TLS・常駐接続・読み書き分離の範囲
新しい例はローカル検体用で、本番TLS方針は含みません。旧例にca/cert/keyが書いてあってもサーバー証明書/ホスト名の検証成功まで保証しないでください。driver/クライアントライブラリ/接続経路ごとに確認し、検証を無効にしません。
CONN_MAX_AGEは接続の再利用期間で、接続プールの導入とは同じではありません。600秒を全環境の最適値とせず、ASGIではDjangoの持続接続の注意も確認します。ルーター例の全readをreplicaへ送る設計には複製遅延やread-after-write、トランザクション/関係の制約があり、allow_relation=Trueだけで別DBの参照整合性が得られません。実replication/ASGI/TLSは今回未検証です。
以前の例と補足
以下の章/コードを保持し、driver互換性や接続確認の誤った説明は訂正しています。公開パスワード、GRANT ALL、%の追加、FLUSH、migrateを接続失敗に対する一連の操作として実行しません。
旧例の注意:組込みbackend用driverと他driverの対応条件を区別しています。公開サンプルへ本番設定を一括置換しません。
| この記事の要点 |
|
前提
- MySQL / MariaDB がインストール済み・起動中
- データベースとユーザーが作成済み
- Django プロジェクトが既に
django-admin startproject済み
1. パッケージインストール
Django から MySQL に繋ぐにはドライバが必要です:
旧例の注意:OS用コマンドは選択肢で一括実行しません。実Python/ABI/OSでwheelやbuild要件を確認し、mysqlclient/PyMySQL両方の導入を必須にしません。
# 推奨: mysqlclient (C 実装で高速)
pip install mysqlclient
# Ubuntu / Debian で C ヘッダが必要
sudo apt install python3-dev default-libmysqlclient-dev build-essential pkg-config
# Mac (Homebrew)
brew install mysql pkg-config
# Windows は wheel が公式配布されているので普通に
pip install mysqlclient
# 代替: pymysql (Pure Python、ビルド不要)
pip install pymysql
pymysql を使う場合の追加設定
次のPyMySQL shimは旧構成の記録です。全Django版や認証/型/TLSの互換を保証せず、要件検査を偽って回避しません。新しい検証はmysqlclientを使っています:
旧例の注意:旧PyMySQL shimです。互換確認済みと扱わず、version_infoを書き換えて検査を回避しません。manage.py/wsgi.pyへ一律に追加する推奨でもありません。
# myproject/__init__.py (プロジェクトのルート)
import pymysql
pymysql.install_as_MySQLdb()
2. settings.py の DATABASES 設定
旧例の注意:2つのDATABASES定義は代替例です。公開パスワードを使わず、OPTIONSの優先やsql_mode上書きの影響も調べます。環境変数だけで秘密保護が完成したとは扱いません。
# myproject/settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mydb',
'USER': 'myuser',
'PASSWORD': 'mypassword',
'HOST': '127.0.0.1', # またはサーバ IP / ホスト名
'PORT': '3306',
'OPTIONS': {
'charset': 'utf8mb4',
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
},
}
}
# 環境変数経由が安全
import os
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': os.environ['DB_NAME'],
'USER': os.environ['DB_USER'],
'PASSWORD': os.environ['DB_PASSWORD'],
'HOST': os.environ.get('DB_HOST', '127.0.0.1'),
'PORT': os.environ.get('DB_PORT', '3306'),
'OPTIONS': {
'charset': 'utf8mb4',
},
}
}
3. データベースとユーザーを作成
旧例の注意:shellのmysql起動とSQLが混在する旧記録です。広いGRANT/公開パスワード/%追加を実行せず、通常のCREATE USER/GRANT後のFLUSHは不要です。
-- MySQL に root でログイン
mysql -u root -p
-- DB 作成(utf8mb4 で絵文字対応)
CREATE DATABASE mydb
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
-- ユーザー作成
CREATE USER 'myuser'@'localhost' IDENTIFIED BY 'mypassword';
-- 権限付与(DB 全体)
GRANT ALL PRIVILEGES ON mydb.* TO 'myuser'@'localhost';
-- リモート接続も許可するなら(本番では注意)
CREATE USER 'myuser'@'%' IDENTIFIED BY 'mypassword';
GRANT ALL PRIVILEGES ON mydb.* TO 'myuser'@'%';
-- 反映
FLUSH PRIVILEGES;
\q
4. マイグレーション実行
旧例の注意:migrateはschemaを変更する作業で、接続確認ではありません。新しい読取例を先に使い、既存本番DBへ接続試験のために実行しません。
# 接続確認 + 標準テーブル作成
python manage.py migrate
# 出力例:
# Operations to perform:
# Apply all migrations: admin, auth, contenttypes, sessions
# Running migrations:
# Applying contenttypes.0001_initial... OK
# ...
# Applying sessions.0001_initial... OK
# 接続成功!
5. 動作確認
旧例の注意:dbshellには外部クライアント等も必要です。Python側の接続成功とCLI経路を区別し、表示8.0.36を実測値や全環境共通としません。
# シェルから直接 SQL を叩く
python manage.py dbshell
mysql> SHOW TABLES;
mysql> exit
# Django shell から
python manage.py shell
>>> from django.db import connection
>>> with connection.cursor() as c:
... c.execute("SELECT VERSION()")
... print(c.fetchone())
...
('8.0.36',)
本番用の追加設定
旧例の注意:600秒は全環境の推奨値ではなく、ASGI/driver/サーバー上限も確認します。TLSのca/cert/key記述だけでホスト名検証を保証しません。組合せSETは今回受理されましたが、sql_modeの他の規則を落とさず実値/要件を確認します。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': os.environ['DB_NAME'],
'USER': os.environ['DB_USER'],
'PASSWORD': os.environ['DB_PASSWORD'],
'HOST': os.environ['DB_HOST'],
'PORT': os.environ.get('DB_PORT', '3306'),
# コネクション維持(最大 600 秒)
'CONN_MAX_AGE': 600,
# SSL 接続
'OPTIONS': {
'charset': 'utf8mb4',
'ssl': {
'ca': '/etc/mysql/ca.pem',
'cert': '/etc/mysql/client-cert.pem',
'key': '/etc/mysql/client-key.pem',
},
# 文字コード周りの厳密設定
'init_command': "SET sql_mode='STRICT_TRANS_TABLES', "
"NAMES utf8mb4 COLLATE utf8mb4_unicode_ci",
},
}
}
# 接続プール(django-db-connection-pool 等を利用)
# pip install django-db-connection-pool
複数 DB の同居(読み書き分離など)
旧例の注意:ルーターの形を示す旧例で、replicaの遅延/整合性/障害を解決しません。全readや全relationを無条件許可せず、異なるDB間のFKを保証しません。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mydb_master',
'HOST': 'mysql-master.example.com',
# ...
},
'replica': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mydb_replica',
'HOST': 'mysql-replica.example.com',
# ...
},
}
DATABASE_ROUTERS = ['myapp.routers.MasterReplicaRouter']
# myapp/routers.py
class MasterReplicaRouter:
def db_for_read(self, model, **hints):
return 'replica'
def db_for_write(self, model, **hints):
return 'default'
def allow_relation(self, obj1, obj2, **hints):
return True
def allow_migrate(self, db, app_label, model_name=None, **hints):
return db == 'default'
よくあるエラー
旧例の注意:原因候補を限定し過ぎていたセルを訂正しています。新DB作成/GRANT/OS依存導入やcharset一括変換を自動対処にしません。
| エラー | 原因 | 対処 |
|---|---|---|
| Can't connect to MySQL server | MySQL 未起動 / ポート不一致 | systemctl status mysql |
| Access denied for user | 有効設定/対象サーバー/認証条件を確認。SQL操作権限は別 | 1045の原因を調べ、全権限や%を自動追加しない |
| Unknown database 'xxx' | 意図した接続先/DB名と存在・権限を確認 | 名前を直さず新規DBを自動作成しない |
| NameError: name '_mysql' is not defined | driverのimport/実体/依存ライブラリ等を確認 | メッセージ/対象Python/OSを照合し、一律のapt導入へ進まない |
| django.db.utils.OperationalError: (2002, ...) | host/socket/port等の接続経路を確認 | 番号だけで原因を限定せず、意図した経路で比較 |
| (1366, "Incorrect string value") | データの符号化/接続/列型等を確認 | 実データと列/接続を照合し、既存DBの一括変換は別途計画 |
utf8mb4 が必須な理由
- MySQL の
utf8は実は 3 バイト UTF-8 だけ → 絵文字(4 バイト)が入らない utf8mb4が真の UTF-8(4 バイト)— 絵文字も OK- 既定charset/utf8の別名は製品・版・設定で異なるため、実値を確認する
- DB/表/列/接続それぞれを調査する。接続のcharsetだけで既存列や照合順序は変わらない
関連
- django-environ:
DATABASE_URL=mysql://user:pass@host/db形式の環境変数を自動展開 - dj-database-url: 同上のパッケージ
- django-db-geventpool: 非同期環境用接続プール
- Django Migrations: モデル変更を SQL に変換
参考:旧構成の書式付き例
元例の注意:元の導入例ですが、両driverをまとめて導入する推奨ではありません。実Python/Django/driverの対応を確認します。
|
pip install pymysql pip install mysqlclient |
元例の注意:元の書式付きsettings例です。PyMySQL shimやSQLite ENGINEの別製品例をMySQLへ一律適用せず、現在の接続条件と要件を確認します。
| settings.py |
|---|
|
import pymysql pymysql.install_as_MySQLdb()
...
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'db_name', # DB名 'USER': 'user', # DBユーザー名 'PASSWORD': 'pass', # パスワード 'HOST': 'localhost', # ホスト名 'PORT': '3306', # ポート 'OPTIONS': { 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'", }, } |
元例の注意:dbshellは外部mysqlクライアントも必要です。driver導入だけで使えると断定せず、実行環境/alias/接続経路を確認します。
|
python manage.py dbshell |
確認範囲と関連ページ
2026年10月26日確認。PHP8.5.12/Laravel13.34.0のvendor bootstrap/PDOとPython3.12.10/Django5.2.18/mysqlclient2.2.7を、新規ローカルMySQL8.4.13の検体にだけ接続しました。新しい掲載ソースの読取、認証1045と操作拒否1142、設定の優先関係、schema/データ/権限の前後不変を確認しています。Laravel全アプリのbootstrap/HTTP/FPM/worker、PyMySQL/MariaDB/全版、実TLS/ASGI/レプリカ、実環境の秘密管理/本番配備は未検証です。CWiki本番のDB設定/認証/権限/接続先を変更せず、config:clearやmigrateを実行していません。
データベースへの接続と操作の子ページから選択できます。MySQL/MariaDBの親ページとDjangoの接続エラーも参照します。
一次資料:Laravelの外部環境変数と設定キャッシュ、Laravelの接続設定とURL解析、Django5.2のdriver/接続/持続接続、Djangoのaliasとルーターの制限、MySQLの接続エラーとpassword表示、MySQL SET文。
子ページはありません
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 3Dグラフィックスのソフト一覧|Blender・Metasequoiaと用途別の選び方
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- Visual Studio「デザイナーを表示できません」エラーの原因と対処 2026-10-28 12:06:00
- SSH 認証に失敗しました。再試行してください の対処 2026-10-28 12:06:00
- SSH2 秘密鍵の読み込みに失敗しました の原因と対処 2026-10-28 12:06:00
- TeraTerm のよくあるエラーと対処法完全ガイド — Connection refused / 2026-10-28 12:06:00
- Visual Studio エラー一覧|コンパイルエラー・警告の確認方法と対処 2026-10-28 11:39:57
- Whitelabel Error Page の原因と消し方|Spring Boot のエラーページ 2026-10-28 11:39:57
- Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法 2026-10-28 11:39:57
- SQL WHERE 句完全ガイド 2026-10-28 11:39:57
- SQL JOIN 完全ガイド (INNER/LEFT/RIGHT/FULL OUTER) 2026-10-28 11:39:57
- tomcat の起動 / 停止ログと catalina.log・catalina.out の違い 2026-10-28 10:24:23
- Tomcat の起動確認方法 5 つ|localhost:8080・ポート・プロセス・ログ 2026-10-28 10:24:23
- Oracle 19c COMMITの使い方: 暗黙コミット・自動確定・応答不明時の確認 2026-10-28 09:59:09
- Oracle 19c DELETE文|削除対象の確認・COMMIT前の判断・ROLLBACKの条件 2026-10-28 09:59:09
- Oracle 19c INSERT文|INSERT ALL・SELECT・RETURNINGとMERGEの使い分け 2026-10-28 09:59:09
- Oracle 19cのトランザクション制御|COMMIT・ROLLBACK・分離レベルと接続設定 2026-10-28 09:59:09