
1. 项目概述为什么Django连MySQL这件事值得单独写一篇实战笔记“Django入门到实战二连接MySQL数据库”——这个标题看起来平平无奇但在我带过十几期后端开发训练营、帮上百位转行者搭过第一套生产级Web系统之后我越来越确信绝大多数人卡在Django的第一道真实门槛不是ORM语法也不是视图函数写法而是数据库连接本身。它不像SQLite那样开箱即用也不像PostgreSQL那样有官方强推的默认配置MySQL在Django生态里是那个“最常用、最易出错、最被低估”的环节。你可能已经跑通了python manage.py runserver页面上也看到了“Welcome to Django”但只要一执行python manage.py makemigrations控制台就弹出django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module或者更隐蔽的OperationalError: (2059, Authentication plugin caching_sha2_password cannot be loaded)——这些报错背后不是你代码写错了而是环境、驱动、协议、权限四层嵌套的“隐性依赖”没对齐。而市面上大量教程要么跳过细节直接贴最终配置要么只讲“装pymysql”却不说清为什么pymysql能替代MySQLdb、什么时候必须用mysqlclient、以及Django 4.2对MySQL 8.0认证插件的兼容逻辑。这篇笔记就是为解决这些“查文档不提、搜Stack Overflow要翻二十页、问群没人答”的真实断点而写的。它不讲Django哲学不堆概念图谱只聚焦一件事从零开始把你的Django项目稳稳地、可复现地、符合生产习惯地连上本地或远程MySQL实例。无论你是刚学完Model基础的新手还是正被客户服务器上MySQL版本不一致折磨的在职开发者只要你需要在Django里真正存取数据这篇就是为你准备的操作手册。接下来所有内容都基于我过去三年在某高校实验室、某SaaS初创公司、某政务系统外包项目中反复验证过的路径——没有“理论上可行”只有“我亲手敲过、测过、上线过”。2. 整体设计思路与方案选型为什么不用SQLite为什么不是所有MySQL驱动都一样2.1 为什么必须放弃SQLite转向MySQL很多Django入门教程用SQLite起步这没错——它轻量、免安装、适合教学演示。但一旦你进入实战阶段就会发现三个硬伤并发写入瓶颈SQLite是文件锁机制同一时间只能有一个写操作。当你的后台管理页面批量导入数据、API接口被压测并发请求时database is locked错误会高频出现。而MySQL是服务端进程模型支持真正的行级锁和事务隔离某次我们给一个社区团购后台做压力测试SQLite在200 QPS时响应延迟飙升至8秒换成MySQL后稳定在120ms以内。数据类型与约束能力弱SQLite的INTEGER字段实际存储的是64位整数但不校验范围它支持CHECK约束但某些版本下会被静默忽略。而MySQL的TINYINT(1)明确对应布尔语义DECIMAL(10,2)精准控制金额精度ENUM类型能强制字段值域——这些在金融类、订单类业务中是刚需。我们曾因SQLite未校验手机号长度在上线后收到大量12位“伪号码”数据修复成本远超初期换库成本。运维与协作不可持续SQLite数据库就是一个.db文件。当你需要做定时备份、主从同步、慢查询分析、连接池监控时它没有任何配套工具链。而MySQL自带mysqldump、mysqladmin、performance_schema配合PrometheusGrafana能实时看连接数、QPS、锁等待时间。某次客户要求提供“近30天用户登录行为热力图”用SQLite我们得写脚本解析日志再拼接用MySQL一条SELECT DATE(login_time), COUNT(*) FROM user_login GROUP BY DATE(login_time)加索引就搞定。所以“连接MySQL”不是技术炫技而是从玩具项目迈向真实产品的分水岭。它倒逼你理解连接池、字符集、时区、事务传播这些后端工程师绕不开的基本功。2.2 驱动选型pymysql vs mysqlclient到底该用哪个Django官方文档说“Django supports MySQL 5.7 and higher”但没明说底层用什么驱动。实际上Django通过DATABASES配置中的ENGINE字段来指定驱动模块常见选项有两个# settings.py DATABASES { default: { ENGINE: django.db.backends.mysql, # 这只是Django的抽象层 # 真正干活的是下面安装的Python包 } }mysqlclientC语言编写的原生驱动性能最优内存占用最低与MySQL Server协议兼容性最好。它是Django官方推荐的首选也是生产环境的绝对主流。但它有个致命门槛需要系统级编译依赖。在Ubuntu上要先apt install python3-dev default-libmysqlclient-dev build-essential在macOS上得用brew install mysql-client再配export PATH/opt/homebrew/opt/mysql-client/bin:$PATHWindows用户更是要下载预编译wheel或手动改VS编译器路径。我见过太多学员卡在这一步最后放弃。PyMySQL纯Python实现的MySQL协议驱动pip install pymysql即可跨平台零依赖。它最大的优势是“能跑起来”尤其适合快速验证、CI/CD流水线、Docker容器化部署。但它比mysqlclient慢约15%~20%且某些高级特性如LOAD DATA INFILE、特定压缩协议不支持。更重要的是PyMySQL默认不启用SSL连接而生产环境MySQL通常强制SSL——这点常被忽略。我的实操建议很明确✅本地开发、学习验证、Docker单机部署 → 优先用PyMySQL省去环境折腾专注业务逻辑✅测试环境、预发布环境、正式生产 → 必须用mysqlclient性能、稳定性、安全合规性经得起考验。提示PyMySQL可以通过一行代码“伪装”成mysqlclient让Django无感调用在项目根目录的__init__.py或settings.py顶部添加import pymysql pymysql.install_as_MySQLdb()这样Django就认为你装了MySQLdb模块无需修改ENGINE配置。这是PyMySQL能成为“开发友好替代品”的关键技巧。2.3 版本兼容性Django 4.2 MySQL 8.0 的认证插件陷阱MySQL 8.0默认启用了caching_sha2_password认证插件而老版本MySQLdb及早期mysqlclient只认mysql_native_password。如果你用Django 4.2连接MySQL 8.0大概率遇到这个经典报错OperationalError: (2059, Authentication plugin caching_sha2_password cannot be loaded)这不是Django的bug也不是你的密码错了而是客户端驱动不支持服务端的认证方式。解决方案有两个方案A推荐治本修改MySQL用户认证插件登录MySQL服务端执行ALTER USER your_django_user% IDENTIFIED WITH mysql_native_password BY your_password; FLUSH PRIVILEGES;这条命令把用户认证方式降级为兼容性更好的mysql_native_password。注意%要替换成你实际允许连接的主机比如localhost或192.168.1.%。方案B临时应急升级mysqlclient到2.1.0新版mysqlclient已原生支持caching_sha2_password但要求编译时链接MySQL 8.0的client library。如果你的系统MySQL client库太旧如Ubuntu 20.04默认是libmysqlclient21即使pip install --upgrade mysqlclient也可能无效。此时方案A更可靠。我踩过的坑是在某政务云平台上MySQL服务由第三方托管不允许修改用户认证插件。最后我们被迫在Django项目里打了补丁——用pymysql并手动指定auth_pluginmysql_native_password参数。这说明方案选择永远要结合你的实际部署环境没有银弹只有权衡。3. 核心细节解析与实操要点从配置到验证的每一步都在做什么3.1 DATABASES配置详解每个参数背后的含义与取舍Django的DATABASES字典远不止填个账号密码那么简单。我们逐项拆解一个生产级配置# settings.py DATABASES { default: { ENGINE: django.db.backends.mysql, NAME: myproject_db, # 数据库名必须提前在MySQL中CREATE DATABASE USER: django_app, # MySQL用户名非root PASSWORD: os.getenv(DB_PASSWORD, dev_password), # 密码绝不硬编码 HOST: os.getenv(DB_HOST, 127.0.0.1), # 本地开发用127.0.0.1Docker用service名云服务填内网IP PORT: os.getenv(DB_PORT, 3306), # 默认3306阿里云RDS可能用3306或自定义端口 OPTIONS: { charset: utf8mb4, # 关键支持emoji和四字节UTF-8 init_command: SET sql_modeSTRICT_TRANS_TABLES, # 严格模式避免隐式类型转换 }, TEST: { CHARSET: utf8mb4, COLLATION: utf8mb4_unicode_ci, } } }NAME数据库名Django不会自动创建数据库你必须先用mysql -u root -p -e CREATE DATABASE myproject_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;手动建库。这里指定了utf8mb4字符集因为MySQL的utf8其实是阉割版最多存3字节字符不支持emoji而utf8mb4才是真正的UTF-8。某次我们上线后用户反馈昵称里的表情显示为?根源就是建库时用了utf8。USER用户名绝对不要用root应该创建专用用户并授予最小权限CREATE USER django_app% IDENTIFIED BY strong_password; GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER ON myproject_db.* TO django_app%; FLUSH PRIVILEGES;权限列表里没有GRANT OPTION不能授予权限、没有FILE不能读写文件、没有SUPER不能杀进程这是基本安全红线。PASSWORD密码必须通过环境变量注入。Django提供了os.getenv()但更推荐用django-environ库pip install django-environimport environ env environ.Env() environ.Env.read_env() # 读取.env文件 # 然后 DATABASES[default][PASSWORD] env(DB_PASSWORD).env文件应加入.gitignore杜绝密码泄露。我见过三次因.env被误提交到GitHub导致数据库被黑的事故。HOST与PORT本地开发用127.0.0.1不是localhost因为localhost会触发Unix socket连接而127.0.0.1走TCP行为更一致Docker Compose中MySQL服务名为db则HOST填db云服务如腾讯云CVM填内网IP如10.0.1.5绝不用公网IP安全组限制延迟高。OPTIONS.charset这是Django连接层的字符集声明必须与MySQL服务端、数据库、表的字符集三者一致。否则会出现“存进去是中文查出来是乱码”。我们统一用utf8mb4对应的MySQL服务端配置my.cnf需包含[client] default-character-set utf8mb4 [mysql] default-character-set utf8mb4 [mysqld] character-set-server utf8mb4 collation-server utf8mb4_unicode_ciOPTIONS.init_command设置SQL模式为STRICT_TRANS_TABLES这是Django 4.2的默认推荐。它会让MySQL在插入超长字符串、空值插入非空字段等场景下直接报错而不是静默截断或转成默认值。这对数据质量是强保障——宁可程序崩也不能存脏数据。3.2 连接池配置为什么Django默认不带连接池如何安全引入Django ORM本身不内置连接池。每次HTTP请求Django都会从头建立MySQL连接用完关闭。这在低流量场景没问题但一旦QPS超过50连接建立/销毁的开销TCP三次握手、SSL协商、认证会吃掉大量CPU。我们曾在一个日活5万的后台系统上观测到MySQL连接数峰值达300其中200是瞬时建立又马上关闭的“僵尸连接”。解决方案是引入第三方连接池主流选择是django-db-geventpool基于gevent或django-mysql基于mysqlclient增强。我推荐后者因为它深度集成mysqlclient无需修改Django ORM调用方式支持连接池大小、空闲超时、健康检查等生产级参数文档清晰社区活跃。安装与配置步骤pip install django-mysql# settings.py DATABASES { default: { ENGINE: mysql.connector.django, # 注意ENGINE变了 # ... 其他配置不变 OPTIONS: { charset: utf8mb4, init_command: SET sql_modeSTRICT_TRANS_TABLES, pool_size: 20, # 连接池最大连接数 pool_name: mypool, # 池名多数据库时区分用 pool_reset_session: True, # 每次从池取连接时重置会话变量 } } }注意django-mysql要求ENGINE改为mysql.connector.django且必须安装mysql-connector-python不是mysqlclient。这是它与django-db-geventpool的关键区别——后者仍用mysqlclient但通过gevent协程复用连接。连接池参数解读pool_size20不是越大越好。Linux单机默认最大文件描述符是1024每个MySQL连接占1个fd还要预留给日志、网络等。我们线上一般设为min(20, CPU核心数*4)。pool_reset_sessionTrue防止前一个请求设置的SET NAMES utf8mb4或SET time_zone08:00影响下一个请求这是连接复用的安全前提。pool_timeout30可选从连接池获取连接的最长等待时间超时抛PoolError避免请求卡死。3.3 字符集与排序规则一个emoji引发的血案前面提到utf8mb4但光改配置还不够。我们曾在线上遇到一个诡异问题用户注册时昵称存的是小明但后台管理列表里显示为小明?而数据库直查却是正常的。排查三天最终定位到Django Model字段定义缺失db_collation。MySQL的排序规则Collation决定了字符串比较、排序、索引的行为。utf8mb4_unicode_ci是通用Unicode排序但对emoji支持不完美utf8mb4_0900_as_csMySQL 8.0是大小写敏感、重音敏感的现代排序规则对emoji支持更好。解决方案是在Model中显式指定class UserProfile(models.Model): nickname models.CharField( max_length50, db_collationutf8mb4_0900_as_cs # 关键告诉Django这个字段用此排序规则 ) bio models.TextField() class Meta: db_table user_profile然后执行迁移python manage.py makemigrations python manage.py migrateDjango会生成类似这样的SQLALTER TABLE user_profile MODIFY nickname varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_cs;提示db_collation是Django 4.2新增的字段选项。如果你用老版本只能在MySQL层面统一设置表的排序规则但无法针对单个字段定制。另一个常见问题是时区不一致。Django默认用UTC而中国用户期望东八区时间。如果MySQL服务端时区是SYSTEM即系统时区而Linux系统时区是Asia/Shanghai那么NOW()返回的时间就是08:00但Django ORM存的时间戳是UTC导致时间差8小时。解决方案是MySQL服务端配置my.cnf中加default-time-zone 08:00Djangosettings.py中加TIME_ZONE Asia/Shanghai和USE_TZ True这样Django存UTC时间戳显示时自动转本地时区MySQL也用UTC存储通过CONVERT_TZ(NOW(), 00:00, 08:00)两端对齐。4. 实操过程与核心环节实现从零开始一步步连上你的MySQL4.1 环境准备本地MySQL安装与用户创建以macOS为例我们以macOS为基准因为它的Homebrew生态最成熟。Windows用户请参考MySQL官方InstallerLinux用户用apt或yum。步骤1安装MySQL# 用Homebrew安装推荐版本可控 brew install mysql # 启动服务 brew services start mysql # 首次运行执行安全初始化设置root密码、删除匿名用户等 mysql_secure_installation步骤2创建Django专用数据库和用户# 登录MySQL用刚设的root密码 mysql -u root -p # 执行以下SQL替换your_password为强密码 CREATE DATABASE myproject_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER django_applocalhost IDENTIFIED BY your_password; GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER ON myproject_db.* TO django_applocalhost; FLUSH PRIVILEGES; EXIT;注意django_applocalhost中的localhost表示只允许本机socket连接。如果后续要用127.0.0.1TCP连接需额外授权CREATE USER django_app127.0.0.1 IDENTIFIED BY your_password;GRANT ... ON myproject_db.* TO django_app127.0.0.1;否则会报Access denied for user django_app127.0.0.1。步骤3验证MySQL是否正常工作# 测试TCP连接用127.0.0.1 mysql -u django_app -p -h 127.0.0.1 -P 3306 myproject_db # 测试socket连接用localhost mysql -u django_app -p -h localhost myproject_db如果都能登录说明MySQL服务和用户权限OK。4.2 Django项目配置PyMySQL开发版与mysqlclient生产版双轨配置我们采用“开发用PyMySQL生产用mysqlclient”的双轨策略通过requirements.txt分环境管理依赖。步骤1创建requirements文件# requirements/base.txt基础依赖 Django4.2,5.0 python-decouple3.8 # 更安全的环境变量读取# requirements/dev.txt开发依赖 -r base.txt PyMySQL1.1.0 django-environ0.10.0# requirements/prod.txt生产依赖 -r base.txt mysqlclient2.2.0 gunicorn21.2.0步骤2配置settings.py支持环境变量切换# settings.py import os from decouple import config # 读取环境变量DEV_MODE默认为True DEBUG config(DEBUG, defaultTrue, castbool) ENVIRONMENT config(ENVIRONMENT, defaultdevelopment) if ENVIRONMENT production: # 生产环境用mysqlclient DATABASES { default: { ENGINE: django.db.backends.mysql, NAME: config(DB_NAME), USER: config(DB_USER), PASSWORD: config(DB_PASSWORD), HOST: config(DB_HOST), PORT: config(DB_PORT, default3306), OPTIONS: { charset: utf8mb4, init_command: SET sql_modeSTRICT_TRANS_TABLES, } } } else: # 开发环境用PyMySQL并伪装 import pymysql pymysql.install_as_MySQLdb() DATABASES { default: { ENGINE: django.db.backends.mysql, NAME: config(DB_NAME), USER: config(DB_USER), PASSWORD: config(DB_PASSWORD), HOST: config(DB_HOST, default127.0.0.1), PORT: config(DB_PORT, default3306), OPTIONS: { charset: utf8mb4, init_command: SET sql_modeSTRICT_TRANS_TABLES, } } }步骤3创建.env文件仅开发环境# .env DEBUGTrue ENVIRONMENTdevelopment DB_NAMEmyproject_db DB_USERdjango_app DB_PASSWORDyour_password DB_HOST127.0.0.1 DB_PORT3306步骤4安装依赖并测试连接# 创建虚拟环境 python -m venv venv source venv/bin/activate # macOS/Linux # venv\Scripts\activate # Windows # 安装开发依赖 pip install -r requirements/dev.txt # 启动Django确保settings.py路径正确 python manage.py runserver # 在另一个终端测试数据库连接 python manage.py dbshell # 应该能进入MySQL命令行如果dbshell成功进入说明PyMySQL伪装成功Django已连上MySQL。4.3 创建第一个Model并迁移验证数据流是否通畅我们创建一个极简的Article模型用于验证完整数据流。步骤1编写models.py# myapp/models.py from django.db import models class Article(models.Model): title models.CharField(max_length200, db_collationutf8mb4_0900_as_cs) content models.TextField() created_at models.DateTimeField(auto_now_addTrue) updated_at models.DateTimeField(auto_nowTrue) class Meta: db_table article verbose_name 文章 verbose_name_plural 文章 def __str__(self): return self.title步骤2生成并执行迁移python manage.py makemigrations # 输出Migrations for myapp: # myapp/migrations/0001_initial.py # - Create model Article python manage.py migrate # 输出Applying myapp.0001_initial... OK步骤3验证表结构python manage.py dbshell-- 在MySQL命令行中执行 USE myproject_db; SHOW CREATE TABLE article;你应该看到类似输出CREATE TABLE article ( id bigint NOT NULL AUTO_INCREMENT, title varchar(200) COLLATE utf8mb4_0900_as_cs NOT NULL, content longtext COLLATE utf8mb4_0900_as_cs NOT NULL, created_at datetime(6) NOT NULL, updated_at datetime(6) NOT NULL, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_0900_as_cs;注意COLLATE utf8mb4_0900_as_cs已生效且引擎是InnoDB支持事务和外键。步骤4用Django Shell插入测试数据python manage.py shell from myapp.models import Article a Article.objects.create(titleDjango连接MySQL实战, content本文详细记录了...) a.id 1 Article.objects.count() 1步骤5用MySQL直查确认SELECT * FROM article; -- 应该看到刚插入的记录且title字段显示正常无乱码至此从Django代码→ORM→MySQL驱动→MySQL Server→磁盘存储整个链路已打通。你可以放心进入业务开发了。4.4 Docker Compose一键部署本地模拟生产环境很多开发者说“本地能跑上线就挂”根本原因是开发环境与生产环境不一致。用Docker Compose三分钟搭建一套与生产几乎一致的本地环境。步骤1创建docker-compose.ymlversion: 3.8 services: web: build: . command: gunicorn myproject.wsgi:application --bind 0.0.0.0:8000 --workers 2 volumes: - .:/code ports: - 8000:8000 depends_on: - db environment: - DEBUGFalse - ENVIRONMENTproduction - DB_NAMEmyproject_db - DB_USERdjango_app - DB_PASSWORDprod_password - DB_HOSTdb - DB_PORT3306 db: image: mysql:8.0 restart: always environment: MYSQL_ROOT_PASSWORD: root_password MYSQL_DATABASE: myproject_db MYSQL_USER: django_app MYSQL_PASSWORD: prod_password volumes: - mysql_data:/var/lib/mysql command: --default-authentication-pluginmysql_native_password # 关键强制MySQL 8.0用老认证插件避免pymysql/mysqlclient兼容问题 volumes: mysql_data:步骤2创建DockerfileFROM python:3.11-slim WORKDIR /code COPY requirements/prod.txt . RUN pip install -r prod.txt COPY . . CMD [gunicorn, myproject.wsgi:application, --bind, 0.0.0.0:8000]步骤3启动服务docker-compose up -d --build # 等待MySQL初始化完成约30秒 docker-compose logs -f db # 查看MySQL启动日志 # 然后执行迁移 docker-compose exec web python manage.py migrate docker-compose exec web python manage.py createsuperuser访问http://localhost:8000/admin用刚建的superuser登录就能看到Django Admin界面——这证明Docker内的Django已成功连接容器内的MySQL。这种环境一致性是避免“本地OK线上GG”的终极保障。5. 常见问题与排查技巧实录那些年我们一起踩过的坑5.1 经典报错速查表报错信息根本原因解决方案我的实操心得django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module缺少MySQL驱动或驱动未正确安装开发环境pip install PyMySQLpymysql.install_as_MySQLdb()生产环境apt install python3-dev default-libmysqlclient-devpip install mysqlclient永远先看pip list确认驱动是否在列表里。pip install mysqlclient失败时90%是缺系统依赖别硬试。OperationalError: (1045, Access denied for user django_app127.0.0.1)MySQL用户权限不足或HOST不匹配检查CREATE USER语句中的HOST是否与Django的HOST配置一致执行SELECT User,Host FROM mysql.user;确认用户存在用mysql -u django_app -p -h 127.0.0.1手动测试MySQL的HOST是精确匹配django_applocalhost和django_app127.0.0.1是两个不同用户OperationalError: (2059, Authentication plugin caching_sha2_password cannot be loaded)MySQL 8.0默认认证插件不被驱动支持方案A推荐ALTER USER userhost IDENTIFIED WITH mysql_native_password BY password;方案B升级mysqlclient到2.1.0政务云/金融云常禁用ALTER USER此时只能用PyMySQL并指定auth_plugin参数或联系云厂商开通权限。django.db.utils.OperationalError: (1267, Illegal mix of collations)表、字段、连接层字符集不一致统一设为utf8mb4MySQL服务端my.cnf、数据库CREATE DATABASE ... CHARACTER SET utf8mb4、DjangoOPTIONS.charset、Modeldb_collation建库时的字符集是源头后期修改要ALTER DATABASE ... CHARACTER SET再ALTER TABLE ... CONVERT TO非常麻烦。django.db.utils.OperationalError: (2003, Cant connect to MySQL server on db ([Errno -2] Name does not resolve))Docker Compose中服务名解析失败检查docker-compose.yml中db服务是否定义确认web服务的depends_on是否包含db执行docker-compose exec web ping db测试网络连通性Docker网络是独立的localhost在容器内指向自己不是宿主机。必须用服务名db。5.2 连接超时与拒绝如何诊断是网络问题还是MySQL配置问题当python manage.py dbshell卡住或报Connection refused先别急着重启MySQL。按顺序排查第一步确认MySQL服务状态# macOS brew services list | grep mysql # Linux systemctl status mysql # Docker docker-compose ps db第二步确认MySQL监听地址和端口# macOS/Linux查看MySQL是否监听0.0.0.0:3306 sudo lsof -i :3306 # 正常输出应有mysqld xxx xxxu 20u IPv6 0x... 0t0 TCP *:mysql (LISTEN) # 如果只有127.0.0.1:3306说明只接受本地连接需改my.cnf # bind-address 0.0.0.0 # 允许所有IP第三步telnet测试端口连通性# 从Django所在机器宿主机或容器测试 telnet 127.0.0.1 3306 # 如果连不上说明MySQL没启动或防火墙拦截 # 如果连上了出现空白或MySQL欢迎信息说明网络OK问题在认证或权限 # Docker内测试 docker-compose exec web telnet db 3306第四步检查MySQL错误日志# macOS Homebrew tail -f /usr/local/var/mysql/*.err # Docker docker-compose logs db | tail -20日志里常有线索比如[Warning] IP address 192.168.1.100 could not be resolvedDNS问题或[Note] Access denied for user django_app192.168.1.100权限问题。实操心得我处理过一个案例客户说“Django连不上RDS”我们telnet发现端口通但dbshell报错。最后发现是RDS安全组只放行了3306端口但Django默认用33060X Protocol——这是MySQL 8.0新协议而Django不使用它。根源是客户误开了X Protocol端口误导了排查方向。永远相信基础工具telnet/ping而不是直接猜应用层问题。5.3 性能瓶颈初筛如何判断是Django慢还是MySQL慢当页面加载慢先定位瓶颈在哪儿方法1Django Debug Toolbar开发环境安装django-debug-toolbar它会在页面底部显示SQL查询列表、执行时间、重复查询提示。如果某个视图执行了20条相似SQLN1问题那就是Django ORM写法问题。方法2MySQL慢查询日志生产环境在my.cnf中开启slow_query_log ON slow_query_log_file /var/log/mysql/mysql-slow.log