skip to Main Content

Running MySQL/MariaDB in a Docker container:

docker run -p 3306:3306 --name $(DATABASE_NAME) -v /tmp/mysql:/var/lib/mysql -e MYSQL_DATABASE=$(DATABASE_NAME) -e MYSQL_USER=$(DATABASE_USER) -e MYSQL_ROOT_PASSWORD=$(DATABASE_PASSWORD) -d mariadb:latest > /dev/null

And then running Django version 4 locally with:

manage.py runserver 127.0.0.1:8000

Error

django.db.utils.OperationalError: (2013, "Lost connection to MySQL server at 'reading initial communication packet', system error: 2")

I can successfully connect to the database with MySQL Workbench as well as the command:

mysql -h 127.0.0.1 -P 3306 -u root -p <database>

I am launching Django and the MySQL/MariaDB Docker container from a Makefile.

Makefile

SHELL := /bin/bash

.PHONY: dj-start-local
dj-start-local: start-mysql
    PYTHONPATH=. django_project/src/manage.py runserver 127.0.0.1:8000

.PHONY: start-mysql
start-mysql:
    docker run -p 3306:3306 --name $(DATABASE_NAME) 
        -v /tmp/mysql:/var/lib/mysql 
        -e MYSQL_DATABASE=$(DATABASE_NAME) 
        -e MYSQL_USER=$(DATABASE_USER) 
        -e MYSQL_ROOT_PASSWORD=$(DATABASE_PASSWORD) 
        -d mariadb:latest > /dev/null

2

Answers


  1. Chosen as BEST ANSWER

    The issue may be due to a race condition, where Django is attempting to connect to the database before it is ready. Try waiting a few seconds after starting the Docker container.

    Simple Solution

    Makefile

    .PHONY: start-mysql
    start-mysql:
        docker run -p 3306:3306 --name $(DATABASE_NAME) 
            -v /tmp/mysql:/var/lib/mysql 
            -e MYSQL_DATABASE=$(DATABASE_NAME) 
            -e MYSQL_USER=$(DATABASE_USER) 
            -e MYSQL_ROOT_PASSWORD=$(DATABASE_PASSWORD) 
            -d mariadb:latest
        sleep 4
    

    Better Solution using healthcheck.sh

    In Dan Black's answer, he pointed out that the MariaDB docker container includes a script healthcheck.sh.

    If you only want to check if the MariaDB container can receive connections, then healthcheck.sh can be run without specifying a user (avoiding authorization complications).

    The Makefile below will check for a database connection every second until the database is ready.

    Makefile (advanced version)

    .PHONY: mysql-start
    mysql-start: mysql-stop
        docker run -p 3306:3306 --name $(DATABASE_NAME) 
            -v /tmp/mysql:/var/lib/mysql 
            -e MYSQL_DATABASE=$(DATABASE_NAME) 
            -e MYSQL_USER=$(DATABASE_USER) 
            -e MYSQL_ROOT_PASSWORD=$(DATABASE_PASSWORD) 
            -d mariadb:latest
        while ! docker exec $(DATABASE_NAME) healthcheck.sh --connect 2> /dev/null; do sleep 1; done
    

  2. Use the healthcheck.sh in the container. Use the MARIADB_MYSQL_LOCALHOST_USER=1 to create a mysql@localhost user that the script can use to access the database,

    The healthcheck waits until its fully started regardless of the time.

    Makefile:

    .PHONY: start-mariadb
    start-mariadb:
        docker run -p 3306:3306 --name $(DATABASE_NAME) 
            -e MARIADB_DATABASE=$(DATABASE_NAME) 
            -e MARIADB_USER=$(DATABASE_USER) 
            -e MARIADB_PASSWORD=$(DATABASE_PASSWORD) 
            -e MARIADB_ROOT_PASSWORD=$(DATABASE_PASSWORD) 
            -e MARIADB_MYSQL_LOCALHOST_USER=1 
            -v /tmp/mysql:/var/lib/mysql 
            -d mariadb:latest
        while ! docker exec $(DATABASE_NAME) healthcheck.sh --su=mysql --connect --innodb_initialized; do sleep 1; done
        docker exec --user mysql $(DATABASE_NAME) mariadb -e 'select "hello world"'
    

    Test run:

    $ make start-mariadb 
    docker run -p 3306:3306 --name dd 
        -e MARIADB_DATABASE=dd 
        -e MARIADB_USER=dd 
        -e MARIADB_PASSWORD=dd 
        -e MARIADB_ROOT_PASSWORD=dd 
        -e MARIADB_MYSQL_LOCALHOST_USER=1 
        -d mariadb:latest
    53066fffa293ed061743024e387bd7fb6f1c664efd603c7a657ba88e307be308
    while ! docker exec dd healthcheck.sh --su=mysql --connect --innodb_initialized; do sleep 1; done
    healthcheck connect failed
    healthcheck connect failed
    healthcheck connect failed
    healthcheck connect failed
    docker exec --user mysql dd mariadb -e 'select "hello world"'
    hello world
    hello world
    

    Note: added MARIADB_PASSWORD otherwise the database/user wouldn’t be created.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search