Last modified: Oct 19, 2026

Connect Django to MySQL with mysqlclient

Django ships with SQLite by default. That is fine for learning, but production projects often need MySQL.

mysqlclient is the recommended driver for this job. It is fast, mature, and well supported by Django.

This guide shows you how to connect Django to MySQL with mysqlclient. It covers installation, configuration, migrations, verification, and troubleshooting.

Why Use mysqlclient

Django does not talk to MySQL directly. It needs a database driver behind the django.db.backends.mysql engine.

mysqlclient is the officially recommended driver. It wraps the C client library and delivers strong performance.

Other options exist, like PyMySQL and mysql-connector-python. They work, but mysqlclient is the safest default.

Django's own documentation lists mysqlclient as the first choice. That matters for long-term support.

Prerequisites

You need a working Django project and a MySQL or MariaDB server. You also need build tools and MySQL development headers.

Create a virtual environment before installing anything. This keeps your project dependencies isolated.

# Create and activate a virtual environment
python -m venv django-mysql-env
source django-mysql-env/bin/activate

# On Windows
django-mysql-env\Scripts\activate

Install Django if you have not done so yet.

pip install django

Install mysqlclient

Install the driver with pip inside your active environment. On Linux, install the development headers first.

# Debian or Ubuntu
sudo apt-get install python3-dev default-libmysqlclient-dev build-essential pkg-config

# Then install the driver
pip install mysqlclient

If the installation fails with mysql_config not found, the headers are missing. A complete walkthrough is available in this guide to install mysqlclient in Python across all platforms.

Create the Database and User

Create a dedicated database and user for your project. Never use the root account for an application.

Run these statements in the MySQL shell.

CREATE DATABASE mydatabase CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'myuser'@'localhost' IDENTIFIED BY 'strong-password';
GRANT ALL PRIVILEGES ON mydatabase.* TO 'myuser'@'localhost';
FLUSH PRIVILEGES;

The utf8mb4 charset is important. It supports emoji and all Unicode characters properly.

Older projects sometimes use utf8, which is a limited MySQL encoding. Avoid it for new work.

Configure settings.py

Open your Django settings.py file. Replace the default SQLite block with a MySQL configuration.

# settings.py
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "NAME": "mydatabase",
        "USER": "myuser",
        "PASSWORD": "strong-password",
        "HOST": "127.0.0.1",
        "PORT": "3306",
        "OPTIONS": {
            "charset": "utf8mb4",
            "init_command": "SET sql_mode='STRICT_TRANS_TABLES'",
        },
    }

The ENGINE value activates the mysqlclient backend. Django loads the driver automatically.

The init_command enables strict mode. This makes MySQL reject invalid data instead of silently truncating it.

Use 127.0.0.1 instead of localhost when you want TCP. On many systems, localhost forces a Unix socket connection.

Move Credentials to Environment Variables

Hardcoded passwords are a security risk. Read them from environment variables instead.

This makes your settings portable across development, staging, and production.

# settings.py
import os

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "NAME": os.environ.get("DB_NAME", "mydatabase"),
        "USER": os.environ.get("DB_USER", "myuser"),
        "PASSWORD": os.environ.get("DB_PASSWORD"),
        "HOST": os.environ.get("DB_HOST", "127.0.0.1"),
        "PORT": os.environ.get("DB_PORT", "3306"),
        "OPTIONS": {"charset": "utf8mb4"},
    }

Set the variables in your shell or your deployment platform. Never commit secrets to version control.

export DB_NAME="mydatabase"
export DB_USER="myuser"
export DB_PASSWORD="strong-password"
export DB_HOST="127.0.0.1"

Run Migrations

Django uses migrations to build the database schema. Run them once the settings are in place.

python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying sessions.0001_initial... OK

If migrations complete without errors, the connection works. Django has created all the core tables in MySQL.

Verify the Connection

A quick check confirms that Django can reach MySQL. Open a Django shell and test the connection.

The ensure_connection() method raises an error if the database is unreachable. It is a clean way to validate your configuration.

# python manage.py shell
from django.db import connection

# Force a connection test
connection.ensure_connection()
print("Connected to MySQL:", connection.settings_dict["NAME"])
Connected to MySQL: mydatabase

You can also run a raw SQL query. Use the cursor() method to open a cursor, then call execute() with your SQL.

from django.db import connection

with connection.cursor() as cursor:
    cursor.execute("SELECT VERSION();")
    version = cursor.fetchone()[0]

print("MySQL version:", version)
MySQL version: 8.0.36

The fetchone() method returns the first row as a tuple. Always call close() on cursors you open manually outside a context manager.

Troubleshoot Common Errors

Most connection problems fall into a few categories. Permissions, driver loading, and network access.

Error Loading MySQLdb Module

Django raises this when the driver is missing. Confirm that mysqlclient is installed in the same environment as Django.

Run pip show mysqlclient to check. If it is missing, install it again inside the active environment.

Access Denied for User

This error means the credentials are wrong or the user lacks privileges. Check the username, password, and host.

MySQL treats 'user'@'localhost' and 'user'@'127.0.0.1' as different accounts. Create the right one for your host setting.

Can't Connect to MySQL Server

This usually means MySQL is not running or is not reachable. Confirm the server is up on the correct port.

In Docker or cloud environments, check firewall rules and security groups. Port 3306 must be open to your application.

Incorrect String Value Errors

This error comes from charset mismatches. Use utf8mb4 in both the database and the connection options.

Also confirm that your tables were created with the right charset. Recreating them after a charset change is often the cleanest fix.

Best Practices for a Clean Setup

Set CONN_MAX_AGE to reuse database connections. A value of 60 seconds works well for most web apps.

DATABASES["default"]["CONN_MAX_AGE"] = 60

Enable ATOMIC_REQUESTS when you want each view wrapped in a transaction. This prevents partial writes on errors.

DATABASES["default"]["ATOMIC_REQUESTS"] = True

Keep query logic in views clean. If you filter large datasets, django-filter in Python keeps your views readable and predictable.

Monitor database errors in production. A quick way to start is to install sentry-sdk in Python and capture exceptions from your Django app automatically.

Back up your database before running migrations in production. A failed migration can be expensive to reverse.

Use the same MySQL version across environments. Version drift causes subtle differences in query behavior and collation.

Conclusion

Connecting Django to MySQL with mysqlclient is a clear, repeatable process. Install the driver, create the database, and update your settings.

Move credentials to environment variables. Run migrations and verify the connection with a simple query.

Watch for charset issues and permission errors. Fix them early so they do not reach production.

With these steps, your Django project runs on MySQL reliably and efficiently from day one.