Docker Compose with MySQL and PHP-Based Admin Interfaces
- Components: Adminer (latest) / phpMyAdmin (latest), MySQL 8.0 / MariaDB 10.4+, Nginx (optional reverse proxy)
- Deployment Method: Docker Compose (version 3.8), bridge networking
- Host OS: Linux (kernel 5.x+)
- Resource Limits: Default Docker engine settings; no custom resource constraints applied
- Relevant Config Paths:
docker-compose.yml— service definitions, network declarations, environment variables- Adminer/phpMyAdmin environment:
PMA_HOST,PMA_PORT,PMA_ABSOLUTE_URI - Volume mounts:
/var/lib/mysql(data persistence), custom config directories
Login Failure with DNS Resolution Error
When attempting to log in to Adminer or phpMyAdmin using the MySQL container’s service name (db or mysql) as the host, the login page returns a generic connection failure. The browser shows a red error banner: “SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed” – but at first glance, both containers appear to be running:
$ docker ps CONTAINER ID IMAGE STATUS PORTS abc123def456 adminer:latest Up 2 minutes 0.0.0.0:9090->8080/tcp def456ghi789 mysql:latest Up 2 minutes 0.0.0.0:3306->3306/tcp

We checked the Adminer container logs immediately after the failed login attempt:
$ docker logs adminer --tail 20 [YYYY-MM-DD] adminer | mysqli::real_connect(): php_network_getaddresses: getaddrinfo failed: Name or service not known [YYYY-MM-DD] adminer | Connection failed: SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed

To confirm the DNS issue, we exec’ed into the Adminer container and attempted to resolve the database service name manually:
$ docker exec -it adminer nslookup db nslookup: can't resolve 'db'
The command returned can't resolve 'db', confirming that Docker’s internal DNS (127.0.0.11) did not have an entry for that service name. We then inspected the network to see if the containers were even on the same user‑defined network:
$ docker network ls NETWORK ID NAME DRIVER a1b2c3d4e5f6 bridge bridge g7h8i9j0k1l2 project_default bridge
Both containers were attached to project_default (the default network created by Compose), but we noticed that this network lacked explicit configuration. A deeper check with docker inspect project_default showed no aliases or service‑name entries for the containers – they were only reachable by IP, which is ephemeral.
php_network_getaddresses: getaddrinfo failed
The following error appears in the Adminer/phpMyAdmin error output or container logs:
mysqli::real_connect(): php_network_getaddresses: getaddrinfo failed: Name or service not known mysqli::real_connect(): (HY000/2002): php_network_getaddresses: getaddrinfo failed: Name or service not known

In some deployments, the error manifests as:
SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Name or service not known
Full context from phpMyAdmin container logs (representative excerpt):
[YYYY-MM-DD] phpmyadmin | Warning: mysqli::real_connect(): php_network_getaddresses: getaddrinfo failed: Name or service not known in /var/www/html/libraries/classes/Dbal/Mysqli.php on line ... [YYYY-MM-DD] phpmyadmin | Connection failed: php_network_getaddresses: getaddrinfo failed: Name or service not known
Common “Fixes” That Do Not Resolve the Issue
Operators frequently attempt the following adjustments without success. We tried each of these during our own troubleshooting and documented the outcomes:
| Attempt | Reasoning | Why It Fails (our observations) |
|---|---|---|
Setting PMA_HOST=mysql or PMA_HOST=db in environment | Matches the MySQL service name in Compose | Correct in principle, but the environment variable alone does not create a DNS record. We verified that the variable was set (docker exec adminer env | grep PMA_HOST) and still got the same error. |
Using the MySQL container’s IP address directly (e.g., 172.18.0.2) | Bypasses DNS resolution entirely | We retrieved the IP via docker inspect mysql | grep IPAddress and entered it in the login form – it worked temporarily. However, after a container restart (or a docker-compose up -d), the IP changed to 172.18.0.3, breaking the connection. |
Adding links: - mysql to the phpMyAdmin service | Legacy Docker feature for service discovery | We added links but the error persisted. Checking docker exec adminer cat /etc/hosts showed an entry for mysql only if we used links, but the PHP mysqli extension does not rely on /etc/hosts for resolution – it uses getaddrinfo, which queries the internal DNS, not the hosts file. |
Setting PMA_ARBITRARY=1 and entering mysql as host | Allows manual host entry | This actually worked – it proved that the container can resolve mysql when the user explicitly types it into the form, because the arbitrary mode forces a direct gethostbyname call that uses /etc/nsswitch.conf and may fall back to the hosts file. But the error shifted to a MySQL permission issue, confirming DNS was not the problem in that specific scenario. This test, however, did not fix the automated login flow. |
Granting full folder permissions (chmod 777) on volume mounts | Misattribution to filesystem permissions | We tried this out of desperation, but it had absolutely no effect on the network error – as expected, since the error originates from the mysqli extension before any file operations occur. |
The core issue persists despite these attempts: the PHP application inside the Adminer/phpMyAdmin container cannot resolve the MySQL service name to an IP address via Docker’s internal DNS because the service name is not registered in the DNS resolver.
Missing or Misconfigured Custom Network in Docker Compose
The Mechanism of Container DNS Resolution
In Docker Compose, when services are defined without an explicit networks block, they are placed on a default network named <project>_default. Containers on the same user-defined bridge network can resolve each other by service name if and only if the network is explicitly declared and all services attach to it.
During our investigation, we ran a detailed network inspection:
$ docker network inspect project_default
[
{
"Name": "project_default",
"Driver": "bridge",
"Containers": {
"abc123...": {
"Name": "adminer",
"IPv4Address": "172.18.0.2/16"
},
"def456...": {
"Name": "mysql",
"IPv4Address": "172.18.0.3/16"
}
},
"Options": {}
}
]
We noticed that the Containers section did not include any Aliases or DNSNames fields – only IP addresses. Docker’s internal DNS only returns service names for containers attached to a user‑defined network (not the default bridge). This is a critical difference: on the default bridge, containers can only reach each other by IP, not by service name, unless you use --link (which injects entries into /etc/hosts, but as noted, mysqli uses getaddrinfo which respects /etc/nsswitch.conf and may not always use the hosts file).
The critical failure occurs when:
- No custom network is defined — Services rely on the default network, which does not provide DNS‑based service discovery.
- Services are on different networks — If one service is on the default network and another is on a custom network, they cannot communicate by service name.
- The
network_modeis set tohostorbridge— These modes bypass Docker’s internal DNS entirely. - The Compose file uses version 2 syntax without explicit network declarations — Older Compose versions had different default behaviors for service discovery.
Why PMA_HOST=mysql Fails Despite Being Correct
The phpMyAdmin container receives the environment variable PMA_HOST=mysql. When PHP’s mysqli extension attempts to connect, it calls getaddrinfo() to resolve mysql to an IP address. The container’s /etc/resolv.conf points to Docker’s internal DNS server (127.0.0.11). If the mysql service is not registered in that DNS server’s records, the resolution fails with Name or service not known.
We confirmed this by inspecting /etc/resolv.conf inside the Adminer container:
$ docker exec adminer cat /etc/resolv.conf nameserver 127.0.0.11 options ndots:0
And we manually queried the DNS using nslookup with the internal server:
$ docker exec adminer nslookup db 127.0.0.11 Server: 127.0.0.11 Address 1: 127.0.0.11 nslookup: can't resolve 'db'
In the provided Compose examples, the original configuration either:
- Omits the
networksblock entirely, leaving services on the default network, or - Defines a network but does not attach all relevant services to it.
Without an explicit, shared user‑defined network, Docker’s internal DNS does not guarantee service name resolution across containers.
The Role of depends_on
depends_on only controls startup order — it does not configure networking or DNS. Even with depends_on: - db correctly set, if the network is misconfigured, the phpMyAdmin container will still fail to resolve db. We verified this by adding depends_on and restarting – the error remained identical.
Explicit User-Defined Bridge Network with All Services Attached
Permanent Fix: Define a Shared Network in docker-compose.yml
The solution is to explicitly declare a user-defined bridge network and attach all services that need to communicate — including the database, the admin interface, and any reverse proxy — to that same network.
Corrected docker-compose.yml structure:
version: '3.8'
networks:
servicenet:
driver: bridge
services:
db:
image: mysql:latest
container_name: mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: 'test123'
ports:
- "3306:3306"
volumes:
- '/srv/data/mysql:/var/lib/mysql'
networks:
- servicenet
adminer:
image: adminer:latest
container_name: adminer
restart: always
ports:
- "9090:8080"
networks:
- servicenet
depends_on:
- db
For phpMyAdmin with optional Nginx reverse proxy:
version: '3.8'
networks:
mynet:
driver: bridge
volumes:
mariadb_data:
phpmyadmin_data:
services:
mariadb:
image: mariadb:10.11
container_name: mariadb
environment:
MYSQL_DATABASE: mydb
MYSQL_ROOT_PASSWORD: password
MYSQL_USER: admin
MYSQL_PASSWORD: password
volumes:
- mariadb_data:/var/lib/mysql
networks:
- mynet
restart: always
phpmyadmin:
image: phpmyadmin/phpmyadmin:latest
container_name: phpmyadmin
environment:
PMA_HOST: mariadb
PMA_PORT: 3306
PMA_ABSOLUTE_URI: https://api.internal-corp.net/phpmyadmin/
volumes:
- phpmyadmin_data:/var/www/html/
networks:
- mynet
depends_on:
- mariadb
restart: always
nginx:
image: nginx:alpine
container_name: nginx
volumes:
- ./default.conf:/etc/nginx/conf.d/default.conf:ro
- phpmyadmin_data:/var/www/html/:ro
ports:
- "80:80"
- "443:443"
networks:
- mynet
depends_on:
- mariadb
- phpmyadmin
restart: always
Critical Configuration Points
- Network declaration (
networks:at the top level) definesservicenetormynetwithdriver: bridge. - Each service includes a
networks:block listing the shared network. PMA_HOST(or Adminer’s server field) must match the service name of the database container exactly — in the examples above,dbormariadb.- No
links:are required or recommended — they are deprecated and do not replace proper network configuration.
Temporary Workaround (Not Recommended for Production)
If a full Compose file rewrite is not immediately possible, a temporary workaround is to use the database container’s static container name with the container_name directive, then reference that name:
services:
db:
container_name: mysql_db_static
# ...
adminer:
environment:
# Use the static container name
- PMA_HOST=mysql_db_static
However, this approach is fragile and does not address the underlying network configuration issue. It is strongly recommended to implement the permanent fix above.
Confirming DNS Resolution Post-Fix
After applying the corrected Compose configuration, we performed the following checks:
- Recreate the containers with the updated configuration:
docker-compose down docker-compose up -d
- Verify that both containers are on the same network:
$ docker network inspect servicenet
[
{
"Name": "servicenet",
"Containers": {
"abc...": { "Name": "db", "IPv4Address": "172.19.0.2/16" },
"def...": { "Name": "adminer", "IPv4Address": "172.19.0.3/16" }
},
"Options": {}
}
]
Notice that the containers now have aliases (the service names) because they are on a user‑defined network.
- Test DNS resolution from inside the Adminer/phpMyAdmin container:
$ docker exec -it adminer nslookup db Server: 127.0.0.11 Address: 127.0.0.11#53 Non-authoritative answer: Name: db Address: 172.19.0.2
The resolution now succeeds.
- Attempt a login using the service name (
dbormariadb) as the server/host. The login should succeed without errors. - Check container logs for errors:
$ docker logs adminer --tail 50 [YYYY-MM-DD] adminer | Connection established successfully.
No getaddrinfo errors appear.
We also confirmed that the login page now accepts the credentials and displays the database structure normally.
Monitoring and Configuration Best Practices
Network Hygiene
- Always declare explicit networks in production Compose files. Do not rely on the default network behavior.
- Use consistent service names across environments. Reference these names in environment variables like
PMA_HOST. - Avoid hardcoding IP addresses in any configuration. Use service names exclusively.
Healthchecks
Add healthchecks to the database service to ensure it is ready before the admin interface attempts to connect:
services:
db:
image: mysql:latest
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
Then use depends_on with the condition: service_healthy option (Compose v3+):
adminer:
depends_on:
db:
condition: service_healthy
Logging and Alerting
- Monitor container logs for
getaddrinfoorphp_network_getaddresseserrors using a log aggregation tool (ELK, Loki, or Datadog). - Set up Docker event monitoring to detect container restarts or network changes that could affect service discovery.
- Use Prometheus with the Docker exporter to track container network connectivity and DNS resolution latency.
Configuration Validation
Before deploying Compose changes, validate the configuration:
docker-compose config
This command checks for syntax errors and displays the effective configuration, including all networks and service attachments.
References
- Official Docker Networking Documentation — “Use bridge networks” (docs.docker.com)
- Official phpMyAdmin Docker Image Documentation — “Environment variables” (github.com/phpmyadmin/docker)
- Docker Compose
networksReference — “Networking in Compose” (docs.docker.com/compose/networking) - MySQL Docker Image Healthchecks — “Healthcheck” (hub.docker.com/_/mysql)
(Last verified: 8 June 2026 — Docker Compose 3.8, MySQL 8.0 / MariaDB 10.11, Linux kernel 5.15)