DEV Community

Python-T Point
Python-T Point

Posted on • Originally published at pythontpoint.in

🐍 Configure Django with AWS RDS MySQL — A Step-by-Step Guide

📦 Prerequisites — Why They Matter

configure django with aws rds mysql

A working Python 3 environment, virtualenv for isolation, and an AWS account with permission to create RDS instances are required — that is the complete prerequisite set.

📑 Table of Contents

  • 📦 Prerequisites — Why They Matter
  • 🔧 Django Settings — How to Connect
  • 🔐 Credential Management — Using .env Files
  • 🛡 AWS RDS Configuration — What the Instance Provides
  • 🔒 Security Group Rules — Allowing Django Access
  • 📈 Parameter Group Tweaks — Optimizing MySQL
  • 🚀 Deploying — How to Launch with Environment Variables
  • 🧪 Testing — Verifying the Connection
  • 🟩 Final Thoughts
  • ❓ Frequently Asked Questions
  • How do I rotate the RDS password without downtime?
  • Can I use IAM authentication instead of a MySQL user/password?
  • What is the recommended way to handle migrations in this setup?
  • 📚 References & Further Reading

🔧 Django Settings — How to Connect

Updating settings.py to point at an RDS endpoint is the core of configuring Django with AWS RDS MySQL.

# settings.py
import os
from pathlib import Path BASE_DIR = Path(__file__).resolve().parent.parent SECRET_KEY = os.getenv('DJANGO_SECRET_KEY', 'fallback-secret-key')
DEBUG = os.getenv('DJANGO_DEBUG', 'False') == 'True' ALLOWED_HOSTS = os.getenv('DJANGO_ALLOWED_HOSTS', 'localhost').split(',') DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': os.getenv('RDS_DB_NAME'), 'USER': os.getenv('RDS_USERNAME'), 'PASSWORD': os.getenv('RDS_PASSWORD'), 'HOST': os.getenv('RDS_HOST'), 'PORT': os.getenv('RDS_PORT', '3306'), 'OPTIONS': { 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'", }, }
}
Enter fullscreen mode Exit fullscreen mode

What this does: (Also read: 🚀 Creating aws s3 bucket policy with python boto3 tutorial)

  • ENGINE: selects the MySQL backend; Django will use the MySQL client library.
  • NAME, USER, PASSWORD, HOST, PORT: are pulled from environment variables so no secrets are checked into version control.
  • OPTIONS‑init_command: enforces strict mode, matching the default RDS configuration.

Hard‑coding forces source files to be altered for each environment, while environment variables allow the same codebase to run locally, in CI, and in production without modification.

🔐 Credential Management — Using .env Files

Store the connection details in a file that python‑dotenv can load at runtime.

# .env
DJANGO_SECRET_KEY=super-secret-key
DJANGO_DEBUG=False
DJANGO_ALLOWED_HOSTS=app.example.com
RDS_DB_NAME=mysite
RDS_USERNAME=dbadmin
RDS_PASSWORD=StrongP@ssw0rd!
RDS_HOST=mydb.abcdefghijk.us-east-1.rds.amazonaws.com
RDS_PORT=3306
Enter fullscreen mode Exit fullscreen mode

At runtime, python‑dotenv reads this file and populates os.getenv. The file should be excluded from version control (.gitignore) to keep credentials private.

Key point: Using environment variables decouples deployment configuration from application logic, enabling safer CI/CD pipelines.


🛡 AWS RDS Configuration — What the Instance Provides

AWS RDS MySQL is a managed relational database service that handles backups, patching, and automated failover — that is the definition you need before provisioning. (Also read: ☁️ Building reusable Terraform modules for AWS S3 — made easy)

🔒 Security Group Rules — Allowing Django Access

Open the MySQL port (3306) only to the EC2 security group that runs the Django app. The following CLI commands create a restrictive rule.

$ aws ec2 create-security-group -group-name django-rds-sg -description "Security group for Django app to access RDS"
{ "GroupId": "sg-0a1b2c3d4e5f6g7h8"
}



$ aws ec2 authorize-security-group-ingress -group-id sg-0a1b2c3d4e5f6g7h8 -protocol tcp -port 3306 -source-group sg-12345abcd
{ "Return": true
}
Enter fullscreen mode Exit fullscreen mode

These commands attach an inbound rule to the security group identified by sg-0a1b2c3d4e5f6g7h8. The source-group must be the SG of the EC2 instances running Django.

📈 Parameter Group Tweaks — Optimizing MySQL

AWS provides a default parameter group, but creating a custom one enables the innodb_file_per_table option, which stores each InnoDB table in its own file. This reduces table‑level I/O contention and simplifies storage management.

$ aws rds create-db-parameter-group -db-parameter-group-name django-mysql-pg -db-parameter-group-family mysql8.0 -description "Custom PG for Django"
{ "DBParameterGroup": { "DBParameterGroupName": "django-mysql-pg", "DBParameterGroupFamily": "mysql8.0", "Description": "Custom PG for Django" }
}



$ aws rds modify-db-parameter-group -db-parameter-group-name django-mysql-pg -parameters "ParameterName=innodb_file_per_table,ParameterValue=1,ApplyMethod=pending-reboot"
{ "DBParameterGroupName": "django-mysql-pg"
}
Enter fullscreen mode Exit fullscreen mode

According to the AWS documentation, applying a custom parameter group can reduce disk I/O contention for heavy write workloads. (More onPythonTPoint tutorials)

Key point: Restricting network access and tuning MySQL parameters together give you a secure, performant backend for Django.


🚀 Deploying — How to Launch with Environment Variables

Containerizing the Django app and passing the RDS credentials via Docker ensures the same configuration works on any host. (Also read: 🔧 Monitor Django apps with Prometheus Grafana made easy)

# Dockerfile
FROM python:3.11-slim ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1 WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt COPY . .
CMD ["gunicorn", "mysite.wsgi:application", "--bind", "0.0.0.0:8000"]
Enter fullscreen mode Exit fullscreen mode

What this does:

  • Sets non‑interactive Python flags.
  • Installs dependencies from requirements.txt.
  • Starts gunicorn listening on all interfaces.

Build and run the container, injecting the .env file at runtime.

$ docker build -t mysite .
[+] Building 2.1s (10/10) FINISHED
...
Successfully tagged mysite:latest



$ docker run -d -name mysite \ -env-file .env \ -p 8000:8000 mysite
c3f5a7e2f8b9b2d7f1a4e6c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8
Enter fullscreen mode Exit fullscreen mode

Inspecting logs confirms the connection attempt.

$ docker logs mysite
[-07-17 12:00:01 +0000] [1] INFO: Starting gunicorn 20.1.0
[-07-17 12:00:01 +0000] [1] INFO: Listening at: http://0.0.0.0:8000 (1)
[-07-17 12:00:01 +0000] [1] INFO: Using worker: sync
[-07-17 12:00:01 +0000] [7] INFO: Booting worker with pid: 7
[-07-17 12:00:01 +0000] [7] INFO: Connected to MySQL at mydb.abcdefghijk.us-east-1.rds.amazonaws.com:3306
Enter fullscreen mode Exit fullscreen mode

Hard‑coding the host would require rebuilding the image for each environment, while --env-file lets you swap endpoints without touching the image.


🧪 Testing — Verifying the Connection

Running Django's built‑in database check ensures that the application can reach the RDS instance with the supplied credentials.

$ docker exec -it mysite python manage.py check -database default
System check identified no issues (0 silenced).
Enter fullscreen mode Exit fullscreen mode

If the credentials are wrong, the command fails with a clear error.

$ docker exec -it mysite python manage.py check -database default
SystemCheckError: ERRORS:?: (mysql.connector.errors.ProgrammingError) Access denied for user 'dbadmin'@'%' (using password: YES)
Enter fullscreen mode Exit fullscreen mode

Update the .env values and re‑run until the command succeeds.

Keep the database credentials out of code; environment variables provide a single source of truth across all stages.

Key point: A successful manage.py check proves that Django can authenticate to the RDS endpoint, confirming the network and IAM configuration.


🟩 Final Thoughts

Configuring Django with AWS RDS MySQL involves three tightly coupled layers: secure network access, environment‑driven settings, and a reproducible deployment artifact. By separating secrets from code, you reduce the attack surface and simplify roll‑outs across staging and production.

When the same pattern is applied to other services—PostgreSQL, Redis, or Elasticsearch—the underlying principle remains: let the platform manage the service, and let the application consume it through immutable configuration.

❓ Frequently Asked Questions

How do I rotate the RDS password without downtime?

Use the AWS RDS “Modify DB Instance” operation to set a new master password, then update the .env file and restart the Django containers. Because Django reads credentials at start‑up, a rolling restart of containers applies the new password instantly.

Can I use IAM authentication instead of a MySQL user/password?

Yes. Enable IAM DB authentication on the RDS instance, grant the appropriate IAM role to the EC2 instance, and set ENGINE to django.db.backends.mysql with OPTIONS': {'auth_plugin': 'mysql_clear_password'}. Django will then obtain a temporary token from the AWS SDK.

What is the recommended way to handle migrations in this setup?

Run migrations as part of the container start‑up script, for example by adding python manage.py migrate before launching gunicorn. Ensure the migration command runs only once per deployment to avoid race conditions.

💡 Want to practise this hands-on? DigitalOcean gives new accounts $200 free credit for 60 days — enough to spin up a full Linux/Docker/Kubernetes environment at no cost.

📚 Recommended reading: Best DevOps & cloud books on Amazon — from Linux fundamentals to Kubernetes in production, curated for working engineers.

📚 References & Further Reading

  • Official Django database configuration guide — comprehensive reference for DB settings: docs.djangoproject.com
  • AWS RDS MySQL documentation — details on instance classes, parameter groups, and security: docs.aws.amazon.com
  • Python‑dotenv usage — loading environment variables safely: pypi.org

Top comments (0)