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:
- A reachable Windows host address from WSL2
- A Windows port proxy forwarding requests correctly
- 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.