Getting Started with Docker & MySQL: My First Real Setup

Getting Started with Docker & MySQL: My First Real Setup

This is my first real hands-on project with Docker. I’d read about containers before, but reading about something and actually running one that refuses to cooperate are two very different experiences. This post is part journal, part tutorial, written mostly so future me has something to come back to when I inevitably forget how any of this works.

The Problem I Ran Into First

I already had MySQL installed natively on my Mac, running quietly on its default port. So the moment I tried to spin up a MySQL container, Docker and my local machine got into an argument over port 3306.

Before touching anything else, the first thing to do in a situation like this is see what’s actually running:

docker ps

This lists every running container along with the ports it’s using. If you want to see containers that exist but aren’t currently running too, add -a:

docker ps -a

If something looks stuck or broken, checking its logs tells you what actually went wrong instead of guessing:

docker logs <container_name>

I was watching for errors like Access denied, Cannot connect, or Port already allocated: that last one was exactly my problem.

To confirm what was hogging port 3306 outside of Docker entirely:

lsof -i :3306

This showed my native mysqld process sitting on that port. I could have killed it with:

kill -9 <PID>

But instead of fighting my existing MySQL installation, I chose the simpler route: give the container a different port and let both versions of MySQL live side by side.

Creating My First MySQL Container

Here’s the command that actually got things running:

docker run --name mysql \
-e MYSQL_ROOT_PASSWORD=root1234 \
-p 3307:3306 \
-d mysql:latest

Breaking this down piece by piece, since I know I’ll forget the flags later:

Flag What it does
--name mysql Names the container mysql so I can refer to it easily
-e MYSQL_ROOT_PASSWORD=root1234 Sets the root password via an environment variable during setup
-p 3307:3306 Maps port 3307 on my Mac to port 3306 inside the container
-d Runs the container in detached mode (in the background)
mysql:latest The image to use: Docker pulls this from Docker Hub if it isn’t already downloaded

That -p 3307:3306 flag was the actual fix for my port conflict. My native MySQL kept 3306. The container’s internal MySQL still runs on 3306 too, but from outside the container, on my actual Mac, I now reach it through 3307.

My Mac                      Docker Container
localhost:3307   ───────►   MySQL running on :3306

To confirm it was up and healthy:

docker ps

Looking for something like:

STATUS
Up ... (healthy)
0.0.0.0:3307->3306/tcp

Connecting Through MySQL Workbench

With the container running, I opened MySQL Workbench and created a new connection with:

Host: localhost
Port: 3307
User: root
Password: root1234

This connects Workbench to the Docker container’s MySQL, not the one installed directly on my Mac (an important distinction I almost missed). Same tool, same interface, completely different database underneath.

Practicing Basic SQL

Once connected, I ran through the basics to make sure everything actually worked end to end.

Create a database:

CREATE DATABASE testdb;

Select it so future commands apply here:

USE testdb;

Create a table:

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50),
    email VARCHAR(100)
);

Insert some data:

INSERT INTO users (name, email)
VALUES 
('Niraj', 'niraj@example.com'),
('John', 'john@example.com');

Query it back:

SELECT * FROM users;

Output:

+----+-------+-------------------+
| id | name  | email             |
+----+-------+-------------------+
| 1  | Niraj | niraj@example.com |
| 2  | John  | john@example.com  |
+----+-------+-------------------+

Seeing that table populate for the first time, inside a container I’d built myself, was a genuinely satisfying moment.

Working Directly From the Terminal

Workbench is nice, but I also learned I could skip the GUI entirely and talk to MySQL straight from inside the container:

docker exec -it mysql bash

Then, once inside the container’s shell:

mysql -u root -p

Enter the password (root1234), and I’m inside MySQL itself, able to run:

SHOW DATABASES;
CREATE DATABASE practice;
USE practice;

Useful Docker Commands I Now Keep Handy

# See running containers
docker ps

# Stop the MySQL container
docker stop mysql

# Start it again
docker start mysql

# Remove it entirely (careful: this doesn't remove data unless volumes are involved)
docker rm mysql

# Full restart via Docker Compose, if using one
docker compose down
docker compose up --build

What I Actually Learned About Docker Here

The biggest shift in understanding for me was realizing what “image” vs. “container” actually means in practice:

  • An image (like mysql:latest) is a template: Docker downloads it once from Docker Hub.
  • A container is a running instance built from that image, my own isolated little MySQL server, separate from anything installed natively on my Mac.

Before Docker, my machine looked like this:

My Mac
└── MySQL (installed directly) → port 3306

After Docker:

My Mac
├── MySQL (installed directly) → port 3306
└── Docker
    └── MySQL container → port 3307 (Mac) → 3306 (inside container)

The analogy that finally made it click for me: think of my Mac as an apartment building. My native MySQL install is one apartment using room number 3306. Docker let me build a new apartment inside the same building (the MySQL container) and just gave it a different door number (3307) so the two don’t collide. Both exist independently, and neither interferes with the other.

This is exactly why developers reach for Docker in the first place: you can run completely different, isolated database setups side by side without them ever fighting over the same resources:

Project A → MySQL 8.0 container
Project B → MySQL 5.7 container
Project C → PostgreSQL container

My Connection Details for Future Projects

For any Django, Node, or other backend project I connect to this container going forward:

HOST = 127.0.0.1
PORT = 3307
USER = root
PASSWORD = root1234
DATABASE = your_database_name

Example Django settings.py config:

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "NAME": "testdb",
        "USER": "root",
        "PASSWORD": "root1234",
        "HOST": "127.0.0.1",
        "PORT": "3307",
    }
}

What’s Next

The one thing I know I still need to fix: right now, if I delete this container, my data disappears with it. Containers are disposable by design (that’s actually the point of them), but that also means my testdb and users table only exist as long as this specific container does.

The next thing on my list to learn is Docker volumes, which make MySQL data persistent even if the container itself gets removed or rebuilt. Until then, I’m treating this container carefully.


This is my first checkpoint with Docker and databases. Revisiting this later, if something’s confusing, it probably confused me too, the first time. That’s the whole reason this file exists.

Want my posts to show up more often on Google?

One click and Google will surface this site in your Top Stories.

Add as preferred source
Niraj Basnet
Written by

Niraj Basnet

Computer Science student at the University of South Florida, exploring web development, mobile app development, and AI. Aspiring full-stack developer.