Skip to main content

Fixed: Docker Compose Recreates a Container Because a Shell Variable Overrides .env

· 5 min read
Jagdish Kumawat
Founder @ Dewiride

docker compose up printed Recreate when I'd changed nothing, and then root's password stopped working. I had two projects open, and I'd exported one project's .env into my shell. Compose prefers the shell's variables over the .env file, so the other project's container got the wrong values.

What I Was Doing​

I was working with two MySQL projects on one computer. For one of them I'd run this, to use its passwords in a script:

Terminal
set -a; source ./.env; set +a

Then, in the same shell, I started the other project, which has its own .env:

Terminal
docker compose up -d --wait

What I Expected​

Started, since nothing about this project had changed.

What I Got​

Output
Container dewiride-inventory-mysql-1 Recreate
Container dewiride-inventory-mysql-1 Recreated
Container dewiride-inventory-mysql-1 Starting
Container dewiride-inventory-mysql-1 Started
Container dewiride-inventory-mysql-1 Waiting
Container dewiride-inventory-mysql-1 Healthy

And the next sign-in as root, using the password from the container's own settings, failed:

Output
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)

My script had hidden that error with 2>/dev/null, so for a while, all I saw was statements that seemed to do nothing.

docker compose up printing Recreate and Recreated for the container, and the mysql client then refused with ERROR 1045: Access denied for user root@localhost.

What I Checked​

My shell, for MYSQL_ variables, without printing the values:

Terminal
env | cut -d= -f1 | grep '^MYSQL_'

Docker's documentation. On how a value like ${MYSQL_ROOT_PASSWORD} in compose.yaml gets filled in, it says "precedence applies", and the first in its list is "Variables from your shell environment", ahead of the .env file. So a variable set in the shell wins.

What the container received. I reproduced it with a harmless value:

Terminal
export MYSQL_ROOT_PASSWORD=value-from-the-shell
docker compose up -d --wait
docker compose exec mysql sh -c 'printf "the container sees: %s\n" "$MYSQL_ROOT_PASSWORD"'
Output
the container sees: value-from-the-shell

Why It Happens​

Compose compares the configuration it works out with the running container's. A new value for a variable counts as a change, so it replaces the container.

MySQL's data is safe, because it lives in the volume. But the MySQL image only uses these variables when it first creates the database, so the real password didn't change. Now the container's variable says one thing and the server's account says another, and anything using $MYSQL_ROOT_PASSWORD fails with ERROR 1045.

The Fix​

Remove the variables from your shell, or open a new terminal. Then start the project again, and Compose recreates the container with the values from .env:

Terminal
unset MYSQL_ROOT_PASSWORD MYSQL_PASSWORD MYSQL_MIGRATOR_PASSWORD
docker compose up -d --wait

In PowerShell, use Remove-Item Env:MYSQL_ROOT_PASSWORD, and the same for each of the others.

Then avoid the cause: don't export a project's .env. To use one value in a command, read it for that command, and it stays out of your shell's environment:

Terminal
password=$(grep '^MYSQL_PASSWORD=' .env | cut -d= -f2-)

source ./.env on its own, without set -a, is fine too, because variables it sets aren't exported.

After the Fix​

Output
mysql: [Warning] Using a password on the command line interface can be insecure.
1
1

The 1 is the answer to SELECT 1. The password works again.

The mysql client signing in as root and returning 1, after the container was recreated from the .env file.

Common Mistakes​

MistakeWhat happensDo this instead
set -a; source .env in a shell you keep usingEvery Compose project in that shell sees those valuesRead single values, or use a subshell
2>/dev/null on database commands in scriptsErrors vanishKeep errors visible
Changing the password in MySQL to matchTwo wrongs make a confusing setupFix the shell

Troubleshooting​

SymptomLikely causeFix
Recreate with a clean shellcompose.yaml or .env really did changeCompare them with your last commit
ERROR 1045 with a clean shellYou changed the password in .env after the first startThe fix
The variable comes back in every new terminalIt's in your shell's profileRemove it from ~/.zshrc or your PowerShell profile

Conclusion​

Compose takes a variable from your shell before .env. If a container is recreated for no reason and its password stops working, look in env, then unset the variable and start again.

Additional Resources​

Stay Updated

Subscribe to our newsletter for the latest tutorials, tech insights, and developer news.

By subscribing, you agree to our privacy policy. Unsubscribe at any time.