Docker
MySQL
Database Connection
Localhost
Containerization

How to connect locally hosted MySQL database with the docker container

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

Connecting a Dockerized application to a MySQL server running on your host machine is a frequent development setup, especially when containerizing only the app layer first. The main challenge is that localhost inside a container refers to the container itself, not your host. A reliable connection setup requires correct host address, MySQL bind settings, and user privileges.

Understand the Networking Boundary

When your app runs in a container, network namespaces are isolated. So this will fail from inside container:

  • host set to 127.0.0.1
  • host set to localhost

You must point to an address reachable from container that routes to host machine.

Common host targets:

  • Docker Desktop on macOS and Windows: host.docker.internal
  • Linux: host gateway IP, often bridge gateway such as 172.17.0.1 or explicit host-gateway mapping

Configure MySQL to Accept External Connections

By default, MySQL may bind only to loopback interface. Check bind-address in MySQL config and set it to an interface reachable from Docker bridge if needed.

Example in mysqld.cnf:

ini
[mysqld]
bind-address = 0.0.0.0

After changing config, restart MySQL service.

Security note:

  • do this only in controlled development environments unless firewall and access controls are configured properly

Create a MySQL User for Container Access

Do not use broad root access from app containers. Create a dedicated user with limited privileges.

sql
CREATE USER 'appuser'@'%' IDENTIFIED BY 'strong_password';
GRANT SELECT, INSERT, UPDATE, DELETE ON mydb.* TO 'appuser'@'%';
FLUSH PRIVILEGES;

For stricter setup, replace % with expected Docker subnet host pattern.

Example App Container Connection with docker run

bash
1docker run --rm -it \
2  --name myapp \
3  -e DB_HOST=host.docker.internal \
4  -e DB_PORT=3306 \
5  -e DB_NAME=mydb \
6  -e DB_USER=appuser \
7  -e DB_PASSWORD=strong_password \
8  myorg/myapp:dev

Inside your app, build connection string from these environment variables.

Python example:

python
1import os
2import mysql.connector
3
4conn = mysql.connector.connect(
5    host=os.getenv("DB_HOST"),
6    port=int(os.getenv("DB_PORT", "3306")),
7    database=os.getenv("DB_NAME"),
8    user=os.getenv("DB_USER"),
9    password=os.getenv("DB_PASSWORD"),
10)
11
12print("connected:", conn.is_connected())
13conn.close()

Linux-Specific Host Gateway Mapping

On Linux, host.docker.internal may not resolve by default. Add explicit host gateway mapping.

bash
1docker run --rm -it \
2  --add-host=host.docker.internal:host-gateway \
3  -e DB_HOST=host.docker.internal \
4  myorg/myapp:dev

This provides a consistent hostname pattern across operating systems.

Docker Compose Example

yaml
1services:
2  app:
3    image: myorg/myapp:dev
4    environment:
5      DB_HOST: host.docker.internal
6      DB_PORT: "3306"
7      DB_NAME: mydb
8      DB_USER: appuser
9      DB_PASSWORD: strong_password
10    extra_hosts:
11      - "host.docker.internal:host-gateway"

Compose keeps local development config repeatable across teammates.

Troubleshooting Checklist

If connection fails, check each layer:

  1. MySQL service is running on host
  2. MySQL listens on expected interface and port
  3. firewall allows traffic from Docker bridge network
  4. app container resolves host name correctly
  5. database credentials and user host permissions are correct

Useful checks from container:

bash
ping host.docker.internal
nc -zv host.docker.internal 3306

If TCP port is reachable but auth fails, issue is likely user privileges or password.

Security and Development Hygiene

Even in development, avoid storing plaintext credentials directly in source files. Use environment files excluded from version control or local secrets managers.

Also avoid exposing MySQL broadly unless necessary. Restrict host firewall to local development subnets where possible.

Common Pitfalls

  • Using localhost in container expecting it to reach host MySQL.
  • Forgetting to adjust MySQL bind address from loopback-only configuration.
  • Granting user only for localhost and expecting remote container access.
  • Assuming host.docker.internal always resolves on Linux without host-gateway mapping.
  • Debugging app code first when issue is actually network path or MySQL privileges.

Summary

  • Containers cannot reach host services through localhost; use host-reachable address.
  • Configure MySQL bind and user permissions to allow container-originated connections.
  • Use host.docker.internal where available, with host-gateway mapping on Linux.
  • Keep configuration in environment variables for repeatable local setup.
  • Troubleshoot systematically across network, service, and credential layers.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.