Fixing Adminer/phpMyAdmin “php_network_getaddresses: getaddrinfo failed” — Docker Network Misconfiguration

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_HOSTPMA_PORTPMA_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:

AttemptReasoningWhy It Fails (our observations)
Setting PMA_HOST=mysql or PMA_HOST=db in environmentMatches the MySQL service name in ComposeCorrect 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 entirelyWe 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 serviceLegacy Docker feature for service discoveryWe 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 hostAllows manual host entryThis 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 mountsMisattribution to filesystem permissionsWe 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:

  1. No custom network is defined — Services rely on the default network, which does not provide DNS‑based service discovery.
  2. 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.
  3. The network_mode is set to host or bridge — These modes bypass Docker’s internal DNS entirely.
  4. 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 networks block 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

  1. Network declaration (networks: at the top level) defines servicenet or mynet with driver: bridge.
  2. Each service includes a networks: block listing the shared network.
  3. PMA_HOST (or Adminer’s server field) must match the service name of the database container exactly — in the examples above, db or mariadb.
  4. 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:

  1. Recreate the containers with the updated configuration:
docker-compose down
docker-compose up -d
  1. 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.

  1. 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.

  1. Attempt a login using the service name (db or mariadb) as the server/host. The login should succeed without errors.
  2. 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 getaddrinfo or php_network_getaddresses errors 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


(Last verified: 8 June 2026 — Docker Compose 3.8, MySQL 8.0 / MariaDB 10.11, Linux kernel 5.15)