Was this helpful? Support me via buymeacoffee.com and help me create lots more great content!

Intermittent `pdo_mysql` PHP Extension in Docker: Diagnosis and Fix

Key Takeaways

  • When using PHP-FPM Docker images, missing extensions like pdo_mysql are often due to volume mounts overwriting the conf.d folder, not image build issues.
  • docker exec shows the state of the running container, whereas docker run uses a fresh image - a critical distinction when debugging PHP extensions.
  • The reliable fix: copy .ini files into the image first, then mount individual .ini files instead of the whole conf.d directory.
  • Avoid mounting subfolders inside conf.d; PHP only scans .ini files directly in conf.d.

The Symptom

While building a PHP-FPM Docker image for a Symfony application, everything seemed fine:

FROM php:8.4-fpm AS base 

RUN apt-get update && apt-get install -y \
    libicu-dev \
    acl \
    procps \
    && docker-php-ext-install pdo pdo_mysql \ 
    && docker-php-ext-install intl \ 
    && docker-php-ext-install opcache \ 
    && apt-get clean && rm -rf /var/lib/apt/lists/*

However, when checking PHP extensions inside a running container with:

docker exec -it app_scaffold-php-1 php -m

the pdo_mysql extension was missing, even though it had been successfully installed in the Dockerfile.

Running a new container from the same image manually:

docker run app_scaffold-php php -m

showed pdo_mysql and intl correctly loaded.

This created an intermittent extension issue - working in some containers but not others.


Diagnosing the Issue

The main clue came from comparing:

  • docker exec in the Compose container → missing extensions
  • docker run from the image → extensions present

and inspecting /usr/local/etc/php/conf.d inside the containers.

In the working manual container:

/usr/local/etc/php/conf.d/
  docker-php-ext-pdo_mysql.ini
  docker-php-ext-intl.ini
  docker-php-ext-opcache.ini
  scaffold-custom.ini

In the Compose container:

/usr/local/etc/php/conf.d/
  scaffold-dev-xdebug.ini
  scaffold-dev-custom.local.ini

Observation: all default extension .ini files were gone.


Why this happened

The Compose file mounted a host folder:

- ./config/docker/php/:/usr/local/etc/php/conf.d
  • Docker replaces the entire conf.d folder with the mounted folder.
  • Default extension .ini files like docker-php-ext-pdo_mysql.ini were hidden, so PHP could no longer load pdo_mysql or intl.
  • Any attempt to use subfolders inside conf.d also didn't work - PHP only scans .ini files directly inside conf.d, not subfolders.

Things I Tried That Didn’t Work

  1. Mounting the entire conf.d directory

    • Goal: add custom .ini files at runtime
    • Problem: overwrote all default extension .ini files → extensions disappeared
  2. Mounting a subfolder inside conf.d

    • Goal: keep default extensions while adding custom .ini files
    • Problem: PHP does not scan subfolders → custom .ini files were ignored
  3. Mounting after image build without copying .ini first

    • Goal: first-run copy of custom .ini files
    • Problem: empty directories created by volume mount → no .ini files, extensions still missing

The Fix

The working approach involved two steps:

  1. Copy the .ini files, on th host, to the correct locations before image build

  2. Mount individual .ini files instead of the whole directory

volumes:
  - ./config/docker/php/scaffold-dev-custom.local.ini:/usr/local/etc/php/conf.d/scaffold-dev-custom.ini:ro
  - ./config/docker/php/scaffold-dev-xdebug.ini:/usr/local/etc/php/conf.d/scaffold-dev-xdebug.ini:ro
  • Avoids overwriting built-in extension .ini files
  • Allows custom settings to override defaults
  • Works for first-run containers and ongoing development

Lessons Learned

  • Docker volumes replace, not merge - mounting a folder over conf.d hides default extension configs.
  • PHP does not scan subdirectories in conf.d. Always mount individual .ini files if you need custom configs.
  • Always check running container vs image: docker exec shows the container state; docker run uses the built image.

This approach ensures:

  • PHP extensions are always loaded correctly
  • Custom .ini files can be mounted safely
  • First-run scripts and development workflows work reliably

Originally published at https://chrisshennan.com/blog/intermittent-pdomysql-php-extension-in-docker-diagnosis-and-fix