How to Fix WP-CLI “Error Establishing a Database Connection” in WSL2 with LocalWP on Windows

✓ Verified Fix

You install WP-CLI in WSL2, connect it to your LocalWP site, and everything looks correct until WP-CLI refuses to talk to MySQL. Your WordPress site still works in the browser. LocalWP says the site is running. Then WP-CLI throws database connection errors from inside WSL.

The problem is not WordPress itself. The problem is how LocalWP exposes MySQL to WSL2.

The error messages that give it away:

Error: Error establishing a database connection.
mysqlcheck: Got error: 2003: Can't connect to MySQL server on '127.0.0.1:10023' (111) when trying to connect
ERROR 2003 (HY000): Can't connect to MySQL server on '10.255.255.254:10023' (111)

Why this problem happens

LocalWP runs MySQL inside Windows and binds the database service to Windows localhost. WSL2 runs in a separate virtualized Linux network environment. When WP-CLI inside WSL2 tries to connect to localhost, it points to the Linux VM — not the Windows host machine.

Changing DB_HOST to the WSL gateway IP alone does not fix the issue because Windows still blocks external access to the LocalWP MySQL port.

You need three things working together:

  1. A reachable Windows host address from WSL2
  2. A Windows port proxy forwarding requests correctly
  3. WordPress configured to use the reachable host

Once those line up, WP-CLI works normally from WSL2.


Step 1: Install WP-CLI inside WSL2

Open Ubuntu in WSL2 and install WP-CLI:

curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
chmod +x wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp

Verify the install:

wp --info

Expected output includes:

WP-CLI version: 2.12.0
PHP version:    8.1.34

Step 2: Open your LocalWP WordPress root from WSL2

Your Windows drives appear under /mnt/ in WSL2. Navigate to your site’s public folder:

cd "/mnt/e/Documents/localwpsites/your-site/app/public"

Verify the WordPress install is there:

ls

You should see:

wp-config.php  wp-content  wp-admin

Step 3: Find your LocalWP database port

Open LocalWP, select your site, and go to the Database tab. Note the port number shown there — it will be something like 10023. You’ll also need:

Host: localhost
User: root
Password: root

Do not use localhost as the host inside WSL2. It points to the Linux VM, not Windows.


Step 4: Create a Windows port proxy for the LocalWP MySQL port

Open PowerShell as Administrator and create the proxy:

netsh interface portproxy add v4tov4 listenport=10023 listenaddress=0.0.0.0 connectport=10023 connectaddress=127.0.0.1

Allow the port through Windows Firewall:

New-NetFirewallRule -DisplayName "LocalWP MySQL 10023" -Direction Inbound -LocalPort 10023 -Protocol TCP -Action Allow

Verify the proxy is active:

netsh interface portproxy show all

Expected output:

Listen on ipv4:             Connect to ipv4:

Address         Port        Address         Port
--------------- ----------  --------------- ----------
0.0.0.0         10023       127.0.0.1       10023

Verify MySQL is listening:

netstat -ano | findstr 10023

Expected output includes:

TCP    0.0.0.0:10023          0.0.0.0:0              LISTENING
TCP    127.0.0.1:10023        0.0.0.0:0              LISTENING

Restart the Windows IP Helper service so the proxy activates correctly:

Restart-Service iphlpsvc

Step 5: Update wp-config.php to use the reachable Windows host

In your site’s wp-config.php, replace this:

define( 'DB_HOST', 'localhost' );

With this:

define( 'DB_HOST', 'host.docker.internal:10023' );

host.docker.internal resolves correctly between WSL2 and Windows on modern setups. It avoids hardcoding the WSL gateway IP, which changes between sessions and reboots.


Step 6: Verify database access from WSL2

Test the MySQL connection directly first:

mysql -h host.docker.internal -P 10023 -u root -proot

Expected output:

Welcome to the MySQL monitor.
Server version: 8.0.35 MySQL Community Server - GPL

Exit MySQL:

exit;

Now test WP-CLI:

wp db check

Expected output:

Success: Database checked.

Confirm plugin access works:

wp plugin list

If that returns your plugin table, WP-CLI is fully connected and working from WSL2.


FAQ

Why did localhost fail inside WSL2? Inside WSL2, localhost refers to the Linux VM itself, not the Windows host machine where LocalWP runs MySQL. They are on separate network interfaces.

Why use host.docker.internal instead of the WSL gateway IP? The WSL gateway IP changes between sessions and reboots. host.docker.internal stays consistent and resolves correctly on newer WSL2 environments without any manual updates.

Why was the Windows port proxy required? LocalWP binds MySQL to Windows localhost only. WSL2 cannot reach that service directly — the port proxy forwards requests from the WSL2 network interface through to where LocalWP is actually listening.

Does this expose MySQL publicly? No. The firewall rule only allows local access on your machine. It does not open the port to external network traffic unless you explicitly configure that.

How do I run Codex autonomously against the site once everything is connected? Launch Codex inside the WordPress root with full access mode:

codex --sandbox danger-full-access -a never

This gives Codex access to WP-CLI execution, file edits, plugin generation, and debugging workflows directly against your LocalWP site.


Errors you can safely ignore

This warning appears when passing a password inline but does not block database access:

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

This message does not indicate a broken PHP install — the executable is php, not php-cli:

Command 'php-cli' not found

Tested on: Windows 11, WSL2 Ubuntu 24.04, LocalWP, WP-CLI 2.12.0, Codex CLI 0.133.0, PHP 8.1.34, MySQL 8.0.35. Active troubleshooting time: approximately 45 minutes. Tools used: WSL2, WP-CLI, Codex CLI, LocalWP, PowerShell, MySQL.