Code, Explained

Testing MySQL Connectivity Using a Dockerized Python Container

When working with microservices, CI pipelines, or containerized environments, it’s often useful to verify MySQL connectivity independently of your application code.

In this post, we’ll build a lightweight Docker container that:

  • Connects to a MySQL database
  • Accepts all connection parameters at runtime
  • Waits and retries until MySQL is available
  • Fails fast if configuration is missing
  • Supports connection timeouts
  • Lists up to 5 tables if the user has privileges
  • Returns CI-friendly exit codes

This approach is ideal for smoke tests, health checks, and CI/CD pipelines.

Why a Dedicated MySQL Connection Tester?

Common scenarios where this is useful:

  • Verifying database access in CI before running migrations
  • Testing credentials in Kubernetes or Docker Compose
  • Debugging network or permission issues
  • Smoke-testing production or staging databases safely

Instead of baking logic into your app, we use a single-purpose container.

Solution Overview

We will build:

  • A Python-based Docker image
  • Runtime-configurable MySQL connection
  • Built-in retry and timeout logic
  • Optional table listing (non-fatal if permissions are missing)

Final Dockerfile

FROM python:3.11-slim

WORKDIR /app

RUN pip install mysql-connector-python

# Create Python test script
RUN echo "import os" > test_db.py && \
    echo "import sys" >> test_db.py && \
    echo "import time" >> test_db.py && \
    echo "import mysql.connector" >> test_db.py && \
    echo "" >> test_db.py && \
    echo "REQUIRED_VARS = ['MYSQL_HOST', 'MYSQL_USER', 'MYSQL_PASSWORD', 'MYSQL_DATABASE']" >> test_db.py && \
    echo "missing = [v for v in REQUIRED_VARS if not os.getenv(v)]" >> test_db.py && \
    echo "if missing:" >> test_db.py && \
    echo "    print('Missing required environment variables: ' + ', '.join(missing))" >> test_db.py && \
    echo "    sys.exit(1)" >> test_db.py && \
    echo "" >> test_db.py && \
    echo "MAX_RETRIES = int(os.getenv('MYSQL_MAX_RETRIES', 10))" >> test_db.py && \
    echo "RETRY_DELAY = int(os.getenv('MYSQL_RETRY_DELAY', 3))" >> test_db.py && \
    echo "CONNECT_TIMEOUT = int(os.getenv('MYSQL_CONNECT_TIMEOUT', 5))" >> test_db.py && \
    echo "" >> test_db.py && \
    echo "for attempt in range(1, MAX_RETRIES + 1):" >> test_db.py && \
    echo "    try:" >> test_db.py && \
    echo "        print(f'Attempt {attempt}: Connecting to MySQL...')" >> test_db.py && \
    echo "        conn = mysql.connector.connect(" >> test_db.py && \
    echo "            host=os.getenv('MYSQL_HOST')," >> test_db.py && \
    echo "            user=os.getenv('MYSQL_USER')," >> test_db.py && \
    echo "            password=os.getenv('MYSQL_PASSWORD')," >> test_db.py && \
    echo "            database=os.getenv('MYSQL_DATABASE')," >> test_db.py && \
    echo "            port=int(os.getenv('MYSQL_PORT', 3306))," >> test_db.py && \
    echo "            connection_timeout=CONNECT_TIMEOUT" >> test_db.py && \
    echo "        )" >> test_db.py && \
    echo "" >> test_db.py && \
    echo "        if conn.is_connected():" >> test_db.py && \
    echo "            print('MySQL connection successful!')" >> test_db.py && \
    echo "" >> test_db.py && \
    echo "            try:" >> test_db.py && \
    echo "                cursor = conn.cursor()" >> test_db.py && \
    echo "                cursor.execute('SHOW TABLES')" >> test_db.py && \
    echo "                tables = cursor.fetchmany(5)" >> test_db.py && \
    echo "" >> test_db.py && \
    echo "                if tables:" >> test_db.py && \
    echo "                    print('Listing up to 5 tables:')" >> test_db.py && \
    echo "                    for t in tables:" >> test_db.py && \
    echo "                        print(' - ' + t[0])" >> test_db.py && \
    echo "                else:" >> test_db.py && \
    echo "                    print('No tables found in database.')" >> test_db.py && \
    echo "" >> test_db.py && \
    echo "            except mysql.connector.Error as e:" >> test_db.py && \
    echo "                print('Connected, but cannot list tables (permission issue?): ' + str(e))" >> test_db.py && \
    echo "" >> test_db.py && \
    echo "            conn.close()" >> test_db.py && \
    echo "            sys.exit(0)" >> test_db.py && \
    echo "" >> test_db.py && \
    echo "    except Exception as e:" >> test_db.py && \
    echo "        print('Connection failed: ' + str(e))" >> test_db.py && \
    echo "        if attempt == MAX_RETRIES:" >> test_db.py && \
    echo "            print('Max retries reached. Exiting.')" >> test_db.py && \
    echo "            sys.exit(2)" >> test_db.py && \
    echo "        time.sleep(RETRY_DELAY)" >> test_db.py

CMD ["python", "test_db.py"]

Build the Image

docker build -t mysql-test-client .

Run the Container (Passing Parameters at Runtime)

sudo docker run --rm --network=esearchnetwork -e MYSQL_HOST=your_host -e MYSQL_PORT=port2connect -e MYSQL_USER=your_db -e MYSQL_PASSWORD=your_super_secret_password -e MYSQL_DATABASE=your_database -e MYSQL_CONNECT_TIMEOUT=10 -e MYSQL_MAX_RETRIES=5 -e MYSQL_RETRY_DELAY=2 mysql-test-client

Example Output

Successful connection with privileges

Attempt 1: Connecting to MySQL…
MySQL connection successful!
Listing up to 5 tables:
users
orders
products
invoices
logs

Successful connection without table privileges

MySQL connection successful!
Connected, but cannot list tables (permission issue?): SHOW command denied

Exit Codes (CI-Friendly)

Exit CodeMeaning
0Connection successful
1Missing required environment variables
2MySQL unreachable after retries

Best Practices & Improvements

Recommended enhancements:

  • Replace echo with COPY test_db.py for maintainability
  • Query information_schema.tables for limited users
  • Output JSON for CI parsing
  • Add TLS / SSL parameters

Conclusion

This lightweight Docker-based MySQL connection tester is a reliable, reusable, and secure way to validate database access across environments.

It works equally well for:

  • Local development
  • Docker Compose
  • Kubernetes
  • CI/CD pipelines

If you need a cleaner version with a standalone Python file, or a Compose/Kubernetes variant, this setup is easy to extend.

Happy testing

Posted in mysql, PythonTagged , , ,