pythonssllibmysqlclient

Docker is downgrading SSL for MySQL connection


The server

I have a MySQL server v8.4 running in Google Cloud with skip-name-resolve. It requires SSL connections, but without trusted client certificates.

I have a user configured on the server to connect from any IP: 'myuser'@'%'.

I have verified the user can connect from any IP using the mysql DB where SELECT Host, User FROM user returns:

+-----------+----------------------------+
| Host      | User                       |
+-----------+----------------------------+
| %         | myuser                     |
| %         | root                       |
+-----------+----------------------------+

For Google Cloud config, connections are allowed from any IP, set using the CIDR range 0.0.0.0/0.

The client

I have a Python program using SQLAlchemy to connect to the server:

from sqlalchemy import create_engine
from sqlalchemy.orm import Session

with Session(create_engine('mysql://myuser:mypass@X.X.X.X:3306/mydb?ssl=true')) as session:
    result = session.query(MyTable).all()
    print(result)

When running on my local machine, this connects to the remote server without issue and prints the rows. Using a VPN and switching to various IP addresses, this continues to work.

The problem

As soon as I put this client code inside a Docker container, the server starts denying the connections.

sqlalchemy.exc.OperationalError: (MySQLdb.OperationalError) (1045, "Access denied for user 'myuser'@'Y.Y.Y.Y' (using password: YES)")

Y.Y.Y.Y matches my public IP address exactly. Connecting from outside the Docker container from this same IP address does not have any issues.

My Dockerfile:

FROM python:3.12-slim-bullseye

WORKDIR /usr/src/app

ENV PYTHONPATH=.

COPY requirements.txt requirements.txt
COPY myfile.py myfile.py

RUN apt-get update && apt-get install -y pkg-config default-libmysqlclient-dev
RUN pip3 install -r requirements.txt

CMD python3 myfile.py

The database logs show that the request is reaching the server but provides no additional information:

Access denied for user 'myuser'@'Y.Y.Y.Y' (using password: YES)

Disabling the SSL requirement on the server fixes the issue. So it seems that the container is ignoring the ?ssl=true.

How do I get the container's connection to use SSL?


Solution

  • In your connection string, add ?ssl_mode=REQUIRED instead of ?ssl=true. This is the syntax for libmysqlclient (MySQL docs confusingly refer to ssl-mode and sslMode which are not available with libmysqlclient).