---
# === IDENTITY ===
id: software/devops/docker-wordpress/2026
canonical_question: "Docker Compose reference: WordPress + MySQL"
aliases:
  - "docker compose WordPress MySQL setup"
  - "docker-compose.yml for WordPress"
  - "containerized WordPress with MySQL"
  - "WordPress Docker development environment"
  - "docker compose WordPress MariaDB phpMyAdmin"
  - "WordPress WP-CLI Docker container"
  - "self-hosted WordPress Docker"
  - "docker WordPress production deployment"
entity_type: software_reference
domain: software > devops > Docker WordPress
region: global
jurisdiction: global
temporal_scope: 2024-2026

# === VERIFICATION ===
last_verified: 2026-02-27
confidence: 0.94
version: 1.0
first_published: 2026-02-27

# === TEMPORAL VALIDITY ===
temporal_validity:
  status: stable
  last_breaking_change: "Docker Compose V2 replaces V1 (docker compose replaces docker-compose, 2023); MySQL 8.4 LTS released (2024-04); WordPress 6.7 released (2024-11); PHP 8.3 default in wordpress:latest (2024)"
  next_review: 2026-08-26
  change_sensitivity: medium

# === CONSTRAINTS ===
constraints:
  - "NEVER use MYSQL_ALLOW_EMPTY_PASSWORD=yes in production -- always set a strong root password or use Docker secrets"
  - "NEVER hardcode database passwords in docker-compose.yml for production -- use .env files or Docker secrets (_FILE suffix)"
  - "ALWAYS use named volumes for MySQL data and wp-content persistence -- bind mounts risk permission issues and data loss on container recreation"
  - "NEVER expose MySQL port 3306 to 0.0.0.0 in production -- keep it on the internal Docker network only"
  - "ALWAYS use the Docker service name (e.g., 'db') as WORDPRESS_DB_HOST -- never use 'localhost' or '127.0.0.1' from within containers"
  - "WORDPRESS_DB_NAME must already exist on the MySQL server -- the WordPress container will NOT create it (MySQL container creates it via MYSQL_DATABASE)"

# === SKIP CONDITIONS ===
skip_this_unit_if:
  - condition: "Need a generic LAMP stack (not WordPress-specific)"
    use_instead: "software/devops/docker-lamp-stack/2026"
  - condition: "Need WordPress on Kubernetes, not Docker Compose"
    use_instead: "software/devops/kubernetes-wordpress-deployment/2026"
  - condition: "Need a static site generator (Hugo, Jekyll), not a CMS"
    use_instead: "software/devops/docker-static-site/2026"

# === AGENT HINTS ===
inputs_needed:
  - key: "database"
    question: "Which database engine do you need?"
    type: choice
    options: ["MySQL 8.0", "MySQL 8.4 LTS", "MariaDB 10.11 LTS", "MariaDB 11"]
  - key: "environment"
    question: "Is this for development or production?"
    type: choice
    options: ["development", "production"]
  - key: "extras"
    question: "Do you need phpMyAdmin or WP-CLI?"
    type: choice
    options: ["phpMyAdmin", "WP-CLI", "Both", "Neither"]

# === DISTRIBUTION ===
canonical_source: "https://knowledgelib.io/software/devops/docker-wordpress/2026"
suggested_citation: "Source: knowledgelib.io -- AI Knowledge Library (verified 2026-02-27)"

# === RELATED UNITS ===
related_kos:
  depends_on: []
  related_to:
    - id: "software/devops/docker-lamp-stack/2026"
      label: "Docker LAMP Stack (Apache + MySQL + PHP)"
    - id: "software/devops/docker-nginx-ssl/2026"
      label: "Docker Nginx + SSL/TLS Termination"
    - id: "software/devops/docker-elk-stack/2026"
      label: "Docker ELK Stack (Logging)"
  solves: []
  alternative_to:
    - id: "software/devops/docker-ghost/2026"
      label: "Docker Ghost CMS (Node.js alternative to WordPress)"
  often_confused_with:
    - id: "software/devops/docker-lamp-stack/2026"
      label: "Docker LAMP Stack (generic PHP, not WordPress-specific)"

# === SOURCES (7 authoritative sources) ===
# Types: official_docs, technical_blog, rfc_spec, academic_paper, community_resource, industry_report
# Reliability: high, moderate_high, moderate, moderate_low, low, authoritative
sources:
  - id: src1
    title: "WordPress Official Docker Image"
    author: Docker
    url: https://hub.docker.com/_/wordpress/
    type: official_docs
    published: 2025-12-01
    reliability: authoritative
  - id: src2
    title: "Docker Awesome Compose: WordPress + MySQL"
    author: Docker
    url: https://github.com/docker/awesome-compose/tree/master/wordpress-mysql
    type: official_docs
    published: 2025-06-01
    reliability: high
  - id: src3
    title: "How to Dockerize WordPress"
    author: Docker
    url: https://www.docker.com/blog/how-to-dockerize-wordpress/
    type: technical_blog
    published: 2024-09-15
    reliability: high
  - id: src4
    title: "How To Install WordPress With Docker Compose"
    author: DigitalOcean
    url: https://www.digitalocean.com/community/tutorials/how-to-install-wordpress-with-docker-compose
    type: technical_blog
    published: 2024-12-01
    reliability: high
  - id: src5
    title: "MySQL Official Docker Image"
    author: Docker
    url: https://hub.docker.com/_/mysql
    type: official_docs
    published: 2025-12-01
    reliability: authoritative
  - id: src6
    title: "wp-config-docker.php Source Code"
    author: Docker Library
    url: https://github.com/docker-library/wordpress/blob/master/wp-config-docker.php
    type: official_docs
    published: 2025-01-01
    reliability: authoritative
  - id: src7
    title: "WordPress Containerization Best Practices"
    author: Pantheon
    url: https://pantheon.io/learning-center/wordpress/containerize
    type: technical_blog
    published: 2025-03-01
    reliability: moderate_high
---

# Docker Compose: WordPress + MySQL Complete Reference

## TL;DR

- **Bottom line**: A production-ready WordPress stack requires just three services (WordPress, MySQL/MariaDB, optional phpMyAdmin) defined in a single `docker-compose.yml` with named volumes for data persistence and environment-based configuration.
- **Key tool/command**: `docker compose up -d` to start the entire WordPress stack; `docker compose exec wordpress wp` for WP-CLI commands.
- **Watch out for**: Forgetting named volumes for `/var/lib/mysql` and `/var/www/html` -- without them, `docker compose down` destroys all your data and content.
- **Works with**: Docker Engine 20.10+, Docker Compose V2 (built-in `docker compose`), WordPress 6.x, MySQL 8.0/8.4 or MariaDB 10.11/11.x, PHP 8.1-8.3.

## Constraints
<!-- Agents: read this section before recommending any action from this unit.
     These are hard constraints that must not be violated. -->

- NEVER use MYSQL_ALLOW_EMPTY_PASSWORD=yes in production -- always set a strong root password or use Docker secrets
- NEVER hardcode database passwords in docker-compose.yml for production -- use .env files or Docker secrets (_FILE suffix)
- ALWAYS use named volumes for MySQL data and wp-content persistence -- bind mounts risk permission issues and data loss on container recreation
- NEVER expose MySQL port 3306 to 0.0.0.0 in production -- keep it on the internal Docker network only
- ALWAYS use the Docker service name (e.g., 'db') as WORDPRESS_DB_HOST -- never use 'localhost' or '127.0.0.1' from within containers
- WORDPRESS_DB_NAME must already exist on the MySQL server -- the WordPress container will NOT create it (MySQL's MYSQL_DATABASE creates it)

## Quick Reference

| Service | Image | Ports | Volumes | Key Env |
|---|---|---|---|---|
| WordPress | `wordpress:6.7-php8.3-apache` | `8080:80` | `wordpress_data:/var/www/html` | `WORDPRESS_DB_HOST=db` |
| MySQL 8.0 | `mysql:8.0` | Internal only | `db_data:/var/lib/mysql` | `MYSQL_ROOT_PASSWORD`, `MYSQL_DATABASE` |
| MySQL 8.4 LTS | `mysql:8.4` | Internal only | `db_data:/var/lib/mysql` | `MYSQL_ROOT_PASSWORD`, `MYSQL_DATABASE` |
| MariaDB 10.11 | `mariadb:10.11` | Internal only | `db_data:/var/lib/mysql` | `MARIADB_ROOT_PASSWORD`, `MARIADB_DATABASE` |
| MariaDB 11 | `mariadb:11` | Internal only | `db_data:/var/lib/mysql` | `MARIADB_ROOT_PASSWORD`, `MARIADB_DATABASE` |
| phpMyAdmin | `phpmyadmin:5` | `8081:80` | None | `PMA_HOST=db` |
| WP-CLI | `wordpress:cli-php8.3` | None | `wordpress_data:/var/www/html` | Same DB env as WordPress |

**WordPress Environment Variables:**

| Variable | Required | Default | Purpose |
|---|---|---|---|
| `WORDPRESS_DB_HOST` | Yes | — | Database hostname (use service name) |
| `WORDPRESS_DB_USER` | Yes | — | Database username |
| `WORDPRESS_DB_PASSWORD` | Yes | — | Database password |
| `WORDPRESS_DB_NAME` | Yes | — | Database name (must exist) |
| `WORDPRESS_TABLE_PREFIX` | No | `wp_` | Table prefix (change for security) |
| `WORDPRESS_DEBUG` | No | `""` | Set to `1` to enable WP_DEBUG |
| `WORDPRESS_CONFIG_EXTRA` | No | `""` | Additional wp-config.php PHP code |
| `WORDPRESS_*_FILE` | No | — | Load any var from a file (Docker secrets) |

**MySQL Environment Variables:**

| Variable | Required | Default | Purpose |
|---|---|---|---|
| `MYSQL_ROOT_PASSWORD` | Yes* | — | Root user password |
| `MYSQL_DATABASE` | No | — | Database to create on first run |
| `MYSQL_USER` | No | — | Non-root user to create |
| `MYSQL_PASSWORD` | No | — | Password for MYSQL_USER |
| `MYSQL_RANDOM_ROOT_PASSWORD` | No* | — | Generate random root password (logged to stdout) |
| `MYSQL_*_FILE` | No | — | Load any var from a file (Docker secrets) |

## Decision Tree

```
START: What kind of WordPress Docker setup do you need?
├── Development environment (local machine)?
│   ├── YES → Use basic docker-compose.yml with phpMyAdmin + port 8080
│   │   ├── Need WP-CLI? → Add wordpress:cli service sharing same volumes
│   │   └── Need custom plugins? → Use custom Dockerfile extending wordpress image
│   └── NO ↓
├── Production deployment?
│   ├── YES → Use production docker-compose.yml with:
│   │   ├── .env file for secrets (never commit to git)
│   │   ├── Named volumes for data persistence
│   │   ├── restart: unless-stopped on all services
│   │   ├── No phpMyAdmin exposed publicly
│   │   ├── Reverse proxy (Nginx/Traefik) with SSL in front
│   │   └── Health checks on all services
│   └── NO ↓
├── Need MariaDB instead of MySQL?
│   ├── YES → Replace mysql image with mariadb, use MARIADB_* env vars
│   └── NO ↓
├── Need multisite WordPress?
│   ├── YES → Add WORDPRESS_CONFIG_EXTRA with WP_ALLOW_MULTISITE define
│   └── NO ↓
└── DEFAULT → Start with the basic development compose file below
```

## Step-by-Step Guide

### 1. Create the project directory and environment file

Set up the project structure with a `.env` file to keep secrets out of `docker-compose.yml`. [src4]

```bash
mkdir wordpress-docker && cd wordpress-docker

cat > .env << 'EOF'
MYSQL_ROOT_PASSWORD=change_me_root_2026
MYSQL_DATABASE=wordpress
MYSQL_USER=wordpress
MYSQL_PASSWORD=change_me_wp_2026
WORDPRESS_TABLE_PREFIX=wp_
EOF

# Prevent committing secrets
echo ".env" >> .gitignore
```

**Verify**: `cat .env` shows your environment variables. `cat .gitignore` includes `.env`.

### 2. Create the docker-compose.yml

Define the WordPress, MySQL, and optional phpMyAdmin services. [src1] [src2]

```yaml
# docker-compose.yml -- WordPress + MySQL Development Stack
# Usage: docker compose up -d
# Access: http://localhost:8080 (WordPress), http://localhost:8081 (phpMyAdmin)

services:
  db:
    image: mysql:8.0
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
    volumes:
      - db_data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

  wordpress:
    image: wordpress:6.7-php8.3-apache
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: ${MYSQL_USER}
      WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD}
      WORDPRESS_DB_NAME: ${MYSQL_DATABASE}
      WORDPRESS_TABLE_PREFIX: ${WORDPRESS_TABLE_PREFIX:-wp_}
    volumes:
      - wordpress_data:/var/www/html

  phpmyadmin:
    image: phpmyadmin:5
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "8081:80"
    environment:
      PMA_HOST: db
      PMA_PORT: 3306
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}

volumes:
  db_data:
  wordpress_data:
```

**Verify**: `docker compose config` should display the resolved configuration without errors.

### 3. Start the stack

Launch all services in detached mode and wait for health checks to pass. [src3]

```bash
# Start all services
docker compose up -d

# Watch logs until WordPress is ready
docker compose logs -f wordpress

# Check all services are healthy
docker compose ps
```

**Verify**: `curl -s -o /dev/null -w '%{http_code}' http://localhost:8080` returns `302` (redirect to install page) or `200`.

### 4. Complete WordPress installation

Visit `http://localhost:8080` in your browser to run the WordPress installation wizard. Alternatively, automate with WP-CLI: [src1]

```bash
# Add WP-CLI service to run WordPress commands
docker compose run --rm \
  -e WORDPRESS_DB_HOST=db \
  -e WORDPRESS_DB_USER=${MYSQL_USER} \
  -e WORDPRESS_DB_PASSWORD=${MYSQL_PASSWORD} \
  -e WORDPRESS_DB_NAME=${MYSQL_DATABASE} \
  wordpress:cli-php8.3 \
  wp core install \
    --url="http://localhost:8080" \
    --title="My WordPress Site" \
    --admin_user=admin \
    --admin_password=change_me_admin \
    --admin_email=admin@example.com
```

**Verify**: `curl -s http://localhost:8080 | grep -o '<title>.*</title>'` shows your site title.

### 5. Back up your data

Regular backups protect against data loss. Export the database and wp-content files. [src5]

```bash
# Database backup via mysqldump
docker compose exec db \
  mysqldump -u root -p"${MYSQL_ROOT_PASSWORD}" "${MYSQL_DATABASE}" \
  > backup-$(date +%Y%m%d).sql

# WordPress files backup (themes, plugins, uploads)
docker compose exec wordpress \
  tar czf /tmp/wp-content-backup.tar.gz -C /var/www/html/wp-content .
docker compose cp wordpress:/tmp/wp-content-backup.tar.gz ./wp-content-backup.tar.gz

# Verify backup
ls -la backup-*.sql wp-content-backup.tar.gz
```

**Verify**: `head -5 backup-*.sql` shows MySQL dump header with database name.

### 6. Restore from backup

Restore your WordPress database and files from a backup. [src5]

```bash
# Restore database
docker compose exec -T db \
  mysql -u root -p"${MYSQL_ROOT_PASSWORD}" "${MYSQL_DATABASE}" \
  < backup-20260227.sql

# Restore wp-content files
docker compose cp ./wp-content-backup.tar.gz wordpress:/tmp/
docker compose exec wordpress \
  tar xzf /tmp/wp-content-backup.tar.gz -C /var/www/html/wp-content
```

**Verify**: `docker compose exec db mysql -u root -p"${MYSQL_ROOT_PASSWORD}" -e "SELECT COUNT(*) FROM ${MYSQL_DATABASE}.wp_posts;"` returns row count.

## Code Examples

### Docker Compose: Production with .env secrets and health checks

> Full script: [docker-compose-production-with-env-secrets-and-hea.yml](scripts/docker-compose-production-with-env-secrets-and-hea.yml) (48 lines)

```yaml
# docker-compose.prod.yml -- Production WordPress Stack
# Usage: docker compose -f docker-compose.prod.yml up -d
# Requires: .env file with all secrets, reverse proxy with SSL in front
services:
  db:
# ... (see full script)
```

### Custom Dockerfile: WordPress with pre-installed plugins

```dockerfile
# Dockerfile -- WordPress with custom plugins and themes
# Build: docker build -t my-wordpress .
FROM wordpress:6.7-php8.3-apache

# Install WP-CLI
RUN curl -o /usr/local/bin/wp https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar \
    && chmod +x /usr/local/bin/wp

# Install additional PHP extensions
RUN apt-get update && apt-get install -y \
    libwebp-dev libjpeg-dev libpng-dev libfreetype6-dev \
    && docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp \
    && docker-php-ext-install gd \
    && apt-get clean && rm -rf /var/lib/apt/lists/*

# Increase PHP upload limits
RUN echo "upload_max_filesize = 64M" > /usr/local/etc/php/conf.d/uploads.ini \
    && echo "post_max_size = 64M" >> /usr/local/etc/php/conf.d/uploads.ini \
    && echo "memory_limit = 256M" >> /usr/local/etc/php/conf.d/uploads.ini \
    && echo "max_execution_time = 300" >> /usr/local/etc/php/conf.d/uploads.ini

# Copy custom themes and plugins
COPY ./themes/ /usr/src/wordpress/wp-content/themes/
COPY ./plugins/ /usr/src/wordpress/wp-content/plugins/
```

### Docker Compose: WordPress with WP-CLI service

> Full script: [docker-compose-wordpress-with-wp-cli-service.yml](scripts/docker-compose-wordpress-with-wp-cli-service.yml) (46 lines)

```yaml
# docker-compose.yml with dedicated WP-CLI service
# Usage: docker compose run --rm wpcli wp plugin list
services:
  db:
    image: mysql:8.0
# ... (see full script)
```

### Bash: WP-CLI management commands

> Full script: [bash-wp-cli-management-commands.sh](scripts/bash-wp-cli-management-commands.sh) (27 lines)

```bash
# Input:  Running WordPress Docker Compose stack
# Output: Common WordPress management operations
# Install and activate a plugin
docker compose run --rm wpcli plugin install woocommerce --activate
# Update all plugins
# ... (see full script)
```

## Anti-Patterns

### Wrong: Hardcoded passwords in docker-compose.yml

```yaml
# BAD -- passwords visible in version control
services:
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: my_secret_password
      MYSQL_PASSWORD: wordpress123
```

### Correct: Environment variables from .env file

```yaml
# GOOD -- passwords loaded from .env (excluded from git)
services:
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
# .env file contains actual values, listed in .gitignore
```

### Wrong: No volume persistence

```yaml
# BAD -- all data lost when container is removed
services:
  db:
    image: mysql:8.0
    # No volumes defined -- data lives only inside the container
  wordpress:
    image: wordpress:latest
    # No volumes -- uploads, plugins, themes all ephemeral
```

### Correct: Named volumes for all persistent data

```yaml
# GOOD -- data persists across container recreations
services:
  db:
    image: mysql:8.0
    volumes:
      - db_data:/var/lib/mysql
  wordpress:
    image: wordpress:latest
    volumes:
      - wordpress_data:/var/www/html

volumes:
  db_data:      # MySQL databases persist
  wordpress_data:  # Themes, plugins, uploads persist
```

### Wrong: Using 'localhost' as database host inside container

```yaml
# BAD -- WordPress container tries to connect to itself
services:
  wordpress:
    environment:
      WORDPRESS_DB_HOST: localhost
      # ERROR: MySQL is not running inside the WordPress container
```

### Correct: Using Docker service name as database host

```yaml
# GOOD -- Docker DNS resolves 'db' to the MySQL container's IP
services:
  wordpress:
    environment:
      WORDPRESS_DB_HOST: db
      # 'db' matches the service name of the MySQL container
```

### Wrong: Exposing MySQL to the host network in production

```yaml
# BAD -- MySQL accessible from outside the Docker network
services:
  db:
    image: mysql:8.0
    ports:
      - "3306:3306"  # Anyone on the network can connect
```

### Correct: Keep MySQL on internal network only

```yaml
# GOOD -- MySQL only reachable by other containers in the same compose network
services:
  db:
    image: mysql:8.0
    expose:
      - "3306"  # Internal only, no host port mapping
```

## Common Pitfalls

- **WordPress shows "Error establishing a database connection"**: WordPress starts before MySQL is ready. Fix: Add `depends_on` with `condition: service_healthy` and a `healthcheck` on the MySQL service. [src1]
- **File permission errors on wp-content**: WordPress runs as `www-data` (UID 33) but host-mounted volumes may have different ownership. Fix: Use named volumes instead of bind mounts, or run `chown -R 33:33 /var/www/html/wp-content` inside the container. [src3]
- **MySQL data disappears after `docker compose down -v`**: The `-v` flag removes named volumes along with containers. Fix: Never use `docker compose down -v` unless you intentionally want to destroy data. Use `docker compose down` (without `-v`) for normal stops. [src5]
- **WP-CLI runs as root, WordPress runs as www-data**: Files created by WP-CLI have root ownership and WordPress cannot modify them. Fix: Add `user: "33:33"` to the WP-CLI service to match the `www-data` UID inside the WordPress container. [src1]
- **Upload size limited to 2MB**: PHP defaults restrict file uploads. Fix: Add `upload_max_filesize = 64M`, `post_max_size = 64M`, and `memory_limit = 256M` via a custom `php.ini` mounted at `/usr/local/etc/php/conf.d/uploads.ini`. [src4]
- **WordPress cannot send email**: No SMTP server is configured by default. Fix: Install the `wp-mail-smtp` plugin and configure it, or add an SMTP relay container (e.g., `mailhog` for development, `msmtp` for production). [src7]
- **Plugin/theme install fails with "Could not create directory"**: WordPress lacks write permission to `/var/www/html/wp-content`. Fix: Ensure the volume is correctly mounted and permissions are set to `www-data:www-data`. [src3]
- **MySQL 8.0 authentication errors with older WordPress plugins**: MySQL 8.0 defaults to `caching_sha2_password` authentication. Fix: Add `command: --default-authentication-plugin=mysql_native_password` to the MySQL service, or use MySQL 8.4+ which handles this better. [src5]

## Diagnostic Commands

```bash
# Check running services and health status
docker compose ps

# View WordPress container logs
docker compose logs wordpress
docker compose logs db

# Test database connectivity from WordPress container
docker compose exec wordpress \
  php -r "new PDO('mysql:host=db;dbname=wordpress', 'wordpress', getenv('WORDPRESS_DB_PASSWORD'));"

# Check MySQL is accepting connections
docker compose exec db mysqladmin ping -h localhost -u root -p"${MYSQL_ROOT_PASSWORD}"

# Inspect WordPress PHP configuration
docker compose exec wordpress php -i | grep -E 'upload_max|post_max|memory_limit'

# Check disk usage of volumes
docker system df -v | grep -A5 "VOLUME NAME"

# List WordPress plugins and their status
docker compose run --rm wpcli plugin list

# Check WordPress database tables
docker compose exec db mysql -u root -p"${MYSQL_ROOT_PASSWORD}" -e \
  "SELECT table_name, table_rows FROM information_schema.tables WHERE table_schema='wordpress';"

# Verify WordPress file permissions
docker compose exec wordpress ls -la /var/www/html/wp-content/

# Check container resource usage
docker stats --no-stream
```

## Version History & Compatibility

| Component | Version | Status | Notes |
|---|---|---|---|
| WordPress | 6.7 | Current | PHP 8.1-8.3 supported, 8.3 recommended |
| WordPress | 6.6 | Supported | PHP 8.0-8.3, last version supporting PHP 8.0 |
| MySQL | 8.4 LTS | Current LTS | Long-term support through 2032, recommended for production |
| MySQL | 8.0 | EOL April 2026 | Migrate to 8.4 LTS before EOL |
| MySQL | 9.x | Innovation | Short-lived release, not for production |
| MariaDB | 10.11 LTS | Current LTS | Supported through Feb 2028, good MySQL alternative |
| MariaDB | 11.x | Short-term | 1-year support cycle per minor version |
| Docker Compose | V2 | Current | Built into Docker CLI as `docker compose` |
| Docker Compose | V1 | EOL (June 2023) | Standalone `docker-compose` binary, do not use |
| PHP | 8.3 | Current | Default in `wordpress:latest` since 2024 |
| phpMyAdmin | 5.x | Current | Supports MySQL 8.x and MariaDB 10.x/11.x |

## When to Use / When Not to Use

| Use When | Don't Use When | Use Instead |
|---|---|---|
| Need a quick local WordPress development environment | Running >10 high-traffic WordPress sites | Kubernetes with horizontal pod autoscaling |
| Self-hosting WordPress on a single server or VPS | Need a managed WordPress experience | Managed hosting (WP Engine, Kinsta, WordPress.com) |
| Need to test plugins/themes in isolation | Need auto-scaling for traffic spikes | Cloud-managed containers (AWS ECS, Google Cloud Run) |
| Building a reproducible WordPress deployment | Need a static/JAMstack site, not a CMS | Hugo, Next.js, or Astro with a headless CMS |
| Need phpMyAdmin or WP-CLI as part of the stack | Database is managed separately (RDS, Cloud SQL) | WordPress image alone with external DB host |

## Important Caveats

- The `wordpress:latest` tag updates automatically -- pin to a specific version (e.g., `wordpress:6.7-php8.3-apache`) in production to avoid unexpected breaking changes
- Docker Compose V1 (`docker-compose` binary) reached end-of-life in June 2023 -- use Docker Compose V2 (`docker compose` subcommand) which is built into Docker Desktop and Docker Engine
- MySQL 8.0 reaches end-of-life in April 2026 -- migrate production deployments to MySQL 8.4 LTS or MariaDB 10.11 LTS
- WordPress auto-updates (plugins, themes, core) may not work correctly in containers if `/var/www/html` is a read-only volume -- either allow writes to the volume or manage updates via WP-CLI and rebuild
- The `_FILE` suffix for environment variables (Docker secrets) is supported by both the WordPress and MySQL official images but NOT by phpMyAdmin -- use regular environment variables for phpMyAdmin or set secrets differently
- MariaDB uses `MARIADB_*` environment variable prefix (e.g., `MARIADB_ROOT_PASSWORD`) instead of `MYSQL_*` since MariaDB 10.6+ -- the old `MYSQL_*` prefix still works but is deprecated

## Related Units
<!-- Generated from related_kos frontmatter -->

- [Docker LAMP Stack (Apache + MySQL + PHP)](/software/devops/docker-lamp-stack/2026)
- [Docker Nginx + SSL/TLS Termination](/software/devops/docker-nginx-ssl/2026)
- [Docker ELK Stack (Logging)](/software/devops/docker-elk-stack/2026)
- [Docker Ghost CMS (Node.js alternative)](/software/devops/docker-ghost/2026)
