WSL2 Optimization

Run Databases in WSL2 (Postgres/MySQL/Mongo) Without Performance Regret

You can absolutely Run Databases in WSL2 (Postgres/MySQL/Mongo) Without Performance Regret. WSL2 puts a real Linux kernel on your Windows machine, but without the right configuration, databases can feel slow, flaky, or hard to access from Windows apps. This guide shows you how to install and tune PostgreSQL, MySQL/MariaDB, and MongoDB in WSL2, place data in the right filesystem, expose services cleanly to Windows, and avoid the common performance traps. You’ll walk away with a dev setup that’s fast, stable, and easy to use—without needing a separate VM or dual-boot.

By the end, you’ll know:

  • Where to store database files for maximum performance
  • How to configure WSL2 resources with a smart .wslconfig
  • How to enable systemd to run services reliably
  • How to expose ports to Windows, use Docker correctly, and fix DNS/file I/O bottlenecks
  • Concrete, copy-paste steps to run Postgres, MySQL/MariaDB, and MongoDB optimally

Overview

WSL2 runs Linux in a lightweight VM and stores each distro’s filesystem inside a virtual disk called an ext4.vhdx. The biggest performance gotcha is crossing the Windows/Linux filesystem boundary: File I/O between /mnt/c (Windows NTFS) and the Linux ext4 filesystem inside WSL2 is much slower than native. Databases write many small files, so placing their data directories on the wrong side of that boundary can tank performance.

Typical scenarios:

  • Running PostgreSQL with data on /mnt/c leads to high latency and slow queries.
  • Docker bind mounts from C:\ into containers cause slow I/O.
  • Windows apps can’t connect to WSL services because of networking misconfig.
  • WSL uses too much or too little memory, starving your DB or the OS.

The fix is straightforward: Keep database files on the Linux side (inside the distro), tune WSL2’s resources and networking, and only cross the boundary when necessary (e.g., IDE on Windows editing project source). This guide shows exactly how.

Quick Reference Table

Command Purpose Example Output
wsl –status Show WSL version, kernel, and settings Default Version: 2; Kernel version: 5.15.133; WSL version: 2.2.5
wsl –version Show detailed WSL info (Store version) WSL version: 2.2.5.0; Kernel: 5.15.133.1
wsl -l -v List installed distros and versions NAME: Ubuntu; STATE: Running; VERSION: 2
wsl –shutdown Stop all WSL VMs (apply config changes) (no output)
notepad %UserProfile%.wslconfig Edit global WSL config (Windows) Opens .wslconfig in Notepad
cat /etc/wsl.conf Show per-distro WSL settings [boot] systemd=true
systemctl status postgresql Check service status active (running)
psql -h localhost -U postgres Test Postgres from WSL or Windows psql (16.3) Type “help” for help.
mysql -h 127.0.0.1 -u root -p Test MySQL/MariaDB connectivity Welcome to the MySQL monitor…
mongosh “mongodb://127.0.0.1:27017” Test MongoDB connectivity Current Mongosh Log ID…
netsh interface portproxy show v4tov4 View Windows port proxies Listen on IPv4:Port 5432…
Optimize-VHD -Path “C:\Users\You\AppData\Local\Packages…\ext4.vhdx” -Mode Full Reclaim space in ext4.vhdx (PowerShell, Hyper-V needed) (progress output)

Key Concepts & Prerequisites

  • Windows and WSL requirements

    • Windows 11 (recommended) or Windows 10 Version 2004+.
    • Latest WSL from Microsoft Store recommended for features like systemd and mirrored networking.
    • Check: wsl –version and wsl –status.
  • Virtualization support

    • BIOS/UEFI virtualization enabled (Intel VT-x/AMD-V).
    • Windows features: “Virtual Machine Platform” enabled. “Windows Subsystem for Linux” installed.
  • Administrative rights

    • Needed to install features, edit .wslconfig, and manage services/ports.
  • Linux distro

    • Ubuntu 22.04 LTS or similar recommended. Install from Microsoft Store.
  • Tools

    • Package manager (apt), editors (nano/vim), curl.
    • Optional: Docker Desktop with WSL integration, or Docker Engine inside WSL.
  • Hardware guidance (dev workstation)

    • 16 GB RAM or more recommended if you run multiple databases/containers.
    • SSD strongly recommended.

Step-by-Step Guide

  1. Update WSL and your distro
  • Update WSL (Windows PowerShell):
    wsl –update
    wsl –version
  • Reboot if prompted.
  • Update your Linux distro packages (inside WSL):
    sudo apt update && sudo apt -y upgrade
See also  Docker Desktop vs Docker in WSL2: Which Is Faster in 2025?

Explanation: Up-to-date WSL delivers better networking (localhost mirroring), systemd support, and bug fixes.

  1. Configure WSL resources and networking with .wslconfig (Windows)

Explanation: This caps WSL memory to prevent Windows thrashing, enables mirrored networking so services are reachable via localhost, and provides sensible CPU/swap defaults. Increase memory if you run multiple DBs concurrently.

  1. Enable systemd inside the distro
  • Edit /etc/wsl.conf in your Linux distro:
    sudo nano /etc/wsl.conf

    [boot]
    systemd=true

  • Restart WSL:
    wsl –shutdown

  • Verify:
    systemctl –version

Explanation: systemd lets you manage databases as services (enable at boot, restart on failure), making WSL feel like a normal Linux server.

  1. Keep your database data on the Linux filesystem
  • Create data directories inside WSL (not under /mnt/c):

    sudo mkdir -p /srv/postgres /srv/mysql /srv/mongo
    sudo chown -R $USER:$USER /srv/postgres /srv/mysql /srv/mongo

Explanation: Storing data in the WSL filesystem (inside the distro’s ext4.vhdx) avoids the slow cross-OS file I/O that hurts database performance.

  1. Install and configure PostgreSQL (fast on WSL2)
  • Install:

    sudo apt update
    sudo apt -y install postgresql postgresql-contrib

  • Verify service:

    systemctl status postgresql

  • Configure for localhost access:
    sudo sed -i “s/^#listen_addresses =./listen_addresses = ‘127.0.0.1’/g” /etc/postgresql//main/postgresql.conf
    sudo systemctl restart postgresql

  • Move data directory (optional; default is already inside WSL):

    • Check current data dir:
      sudo -u postgres psql -c “show data_directory;”
    • If needed, stop and move:
      sudo systemctl stop postgresql
      sudo rsync -a /var/lib/postgresql/ /srv/postgres/
      sudo sed -i “s|/var/lib/postgresql|/srv/postgres|g” /etc/postgresql/*/main/postgresql.conf
      sudo systemctl start postgresql
  • Create a user/db and test from Windows:
    sudo -u postgres createuser -s $USER
    createdb devdb
    psql -h localhost -U $USER -d devdb -c “select version();”

  • Optional tuning (edit /etc/postgresql/*/main/postgresql.conf):

    • shared_buffers = 25% of memory (e.g., 2GB on 8GB WSL)
    • effective_cache_size = 50–75% of memory
    • work_mem = 16–64MB per connection (start small)
    • checkpoint_timeout = 10-15min; max_wal_size = 1–2GB
  • Enable at boot:
    sudo systemctl enable postgresql

  1. Install and configure MySQL or MariaDB
    Note: Ubuntu’s mysql-server may install MariaDB. Either works for dev.
  • Install:
    sudo apt -y install mysql-server
  • Set to listen on localhost:
    sudo sed -i “s/^bind-address.*/bind-address = 127.0.0.1/” /etc/mysql/mysql.conf.d/mysqld.cnf
    sudo systemctl restart mysql
  • Secure installation:
    sudo mysql_secure_installation
  • Create user/db and test:
    sudo mysql -e “CREATE USER ‘dev’@’localhost’ IDENTIFIED BY ‘devpass’; GRANT ALL PRIVILEGES ON . TO ‘dev’@’localhost’; FLUSH PRIVILEGES;”
    mysql -h 127.0.0.1 -u dev -p -e “SELECT VERSION();”
  • Optional tuning (mysqld.cnf under [mysqld]):
    • innodb_buffer_pool_size = 2G (on 8GB WSL; adjust)
    • innodb_log_file_size = 256M
    • innodb_flush_log_at_trx_commit = 2 (dev)
    • max_connections = 100 (dev)
  • Enable at boot:
    sudo systemctl enable mysql
  1. Install and configure MongoDB (WiredTiger)
  • Add official repo (MongoDB 7.0 example for Ubuntu 22.04):

    curl -fsSL https://pgp.mongodb.com/server-7.0.asc | sudo gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg –dearmor
    echo “deb [signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse” | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
    sudo apt update
    sudo apt -y install mongodb-org

  • Configure localhost binding and data path:
    sudo sed -i “s|^ bindIp:.| bindIp: 127.0.0.1|” /etc/mongod.conf
    sudo sed -i “s|^ dbPath:.
    | dbPath: /srv/mongo|” /etc/mongod.conf
    sudo chown -R mongodb:mongodb /srv/mongo
    sudo systemctl enable –now mongod

  • Optional tuning (in /etc/mongod.conf):
    storage:
    wiredTiger:
    engineConfig:
    cacheSizeGB: 2

  • Test:
    mongosh “mongodb://127.0.0.1:27017” –eval “db.runCommand({ buildInfo: 1 })”

  1. Connecting from Windows apps and tools
    With mirrored networking, Windows connects to WSL services via localhost.
  • PostgreSQL: Host=localhost; Port=5432; User=youruser
  • MySQL/MariaDB: Host=127.0.0.1; Port=3306; User=dev
  • MongoDB: mongodb://127.0.0.1:27017
See also  Speed Up File I/O: Where to Keep Code—Linux vs Windows Paths

If localhost doesn’t work (older WSL), create a port proxy:

  • Find WSL IP (inside WSL): ip -4 addr show eth0
  • Create proxy (Windows PowerShell as Admin):
    netsh interface portproxy add v4tov4 listenport=5432 listenaddress=127.0.0.1 connectaddress= connectport=5432
    Repeat for 3306 and 27017 as needed.
  1. Optional: Run databases with Docker inside WSL2 (fast when volumes are on Linux paths)
  • Ensure Docker Desktop is installed and WSL integration is enabled for your distro. Or install Docker Engine inside WSL.

  • Use Linux-side volumes, not Windows bind mounts:
    mkdir -p ~/data/postgres ~/data/mysql ~/data/mongo

  • Sample docker-compose.yml (place it inside WSL, e.g., ~/projects/dbs):
    services:
    postgres:
    image: postgres:16
    environment:
    POSTGRES_PASSWORD: devpass
    ports:

    • “5432:5432”
      volumes:
    • ~/data/postgres:/var/lib/postgresql/data
      mysql:
      image: mysql:8
      environment:
      MYSQL_ROOT_PASSWORD: devpass
      ports:
    • “3306:3306”
      command: –default-authentication-plugin=mysql_native_password
      volumes:
    • ~/data/mysql:/var/lib/mysql
      mongo:
      image: mongo:7
      ports:
    • “27017:27017”
      volumes:
    • ~/data/mongo:/data/db
  • Start:
    docker compose up -d

Explanation: Avoid bind-mounting C:\ folders into containers; keep data inside WSL for speed.

Troubleshooting

  • DNS in WSL not working (apt fails, names don’t resolve)

    • Regenerate resolv.conf and pin a DNS:
      sudo rm -f /etc/resolv.conf
      echo -e “[network]\ngenerateResolvConf=false” | sudo tee -a /etc/wsl.conf
      echo -e “nameserver 1.1.1.1\nnameserver 8.8.8.8” | sudo tee /etc/resolv.conf
      sudo chattr +i /etc/resolv.conf
      wsl –shutdown
    • If on corporate VPN, try dnsTunneling=true in .wslconfig and/or autoProxy=true.
  • Windows can’t reach WSL services on localhost

    • Ensure mirrored networking in .wslconfig and restart WSL:
      networkingMode=mirrored
      localhostForwarding=true
      wsl –shutdown
    • Check service is listening:
      ss -tulpen | grep -E “5432|3306|27017”
    • As a fallback, use netsh portproxy (see Step 8).
  • Disk space bloat in ext4.vhdx

    • Clean package caches in WSL:
      sudo apt clean && sudo journalctl –vacuum-size=100M
    • Compact VHD (requires Hyper-V PowerShell):
      wsl –shutdown
      Optimize-VHD -Path “C:\Users\You\AppData\Local\Packages\\LocalState\ext4.vhdx” -Mode Full
    • Alternatively, export/import:
      wsl –shutdown
      wsl –export C:\backup.tar
      wsl –unregister
      wsl –import C:\WSL C:\backup.tar –version 2
  • Git or build tools are slow in WSL

    • Don’t keep repos under /mnt/c if you build inside WSL; store under ~ or /home.
    • If you must use Windows paths, enable metadata and sensible masks:
      In /etc/wsl.conf:
      [automount]
      options = “metadata,umask=22,fmask=11”
      Then wsl –shutdown.
    • Git tips:
      git config –global core.autocrlf input
      git config –global core.fscache true
  • File I/O slowness with Docker

    • Avoid Windows bind mounts to containers. Use named volumes or paths under /home.
    • Exclude your WSL or Docker data directories in Windows Defender to reduce scanning impact on bind mounts:
      Windows Security > Virus & threat protection > Manage settings > Exclusions.
  • Services don’t start automatically

    • Ensure systemd is enabled:
      cat /etc/wsl.conf should show [boot] systemd=true
      systemctl enable postgresql mysql mongod
    • Restart WSL:
      wsl –shutdown
  • Time drift or clock issues

    • Restart WSL and restart services:
      wsl –shutdown
      sudo systemctl restart postgresql mysql mongod

Optimization & Best Practices

  • Filesystem placement

    • Keep database data on Linux (inside WSL’s ext4.vhdx). Never place DB data files under /mnt/c.
    • Keep source code wherever your workflow benefits (Windows for IDEs; Linux if building inside WSL).
  • Memory and CPU tuning

    • Use .wslconfig to cap memory and assign CPU cores to avoid thrashing.
    • Size DB caches to fit within the WSL memory cap.
    • Prefer moderate swap (2–4 GB). Excessive swap may harm performance.
  • Networking

    • Use networkingMode=mirrored and localhostForwarding=true for simple Windows connectivity.
    • Avoid binding services to 0.0.0.0 unless you need external access; 127.0.0.1 is safer for dev.
  • Docker volumes

    • Place volumes in Linux paths for speed. For Windows IDE access to code, use bind mounts for code only, not for DB data.
  • Logging and journaling

    • Limit excessive logs: journalctl –vacuum-time=7d or size limits.
    • For dev, relaxed durability settings (e.g., PostgreSQL synchronous_commit=off for local dev) can speed up tests/builds. Don’t use in production.
  • Compaction and housekeeping

    • Periodically compact ext4.vhdx if space grows.
    • Clean apt caches and old kernels.
  • Security and exposure

    • Keep databases bound to 127.0.0.1 unless you explicitly need network access.
    • Use strong passwords even for dev; consider local-only accounts.
  • Backups and resets

    • Use pg_dump/mysqldump/mongodump or docker volume backups for quick resets.
    • Export/import WSL distros for snapshot-like backups.
  • Tooling integration

    • For IDEs (VS Code, JetBrains), consider the WSL extension for faster file operations on Linux-side paths.
See also  How to Shrink and Compact ext4.vhdx Without Data Loss

Project-Based Example: Node.js + PostgreSQL on WSL2 with Fast Local DB

Goal: Run a typical Node.js app with PostgreSQL in WSL2, fast builds, and easy Windows access.

  1. Prepare WSL2 for performance
  • Ensure .wslconfig with 8GB memory, mirrored networking, and systemd enabled in /etc/wsl.conf.
  • Restart WSL:
    wsl –shutdown
  1. Create a project on Windows for IDE convenience
  • On Windows, create C:\projects\nodeapp and open in your IDE.
  • In WSL, access it at /mnt/c/projects/nodeapp. For performance-critical build steps, consider running the build in WSL but keep DB data in Linux.
  1. Install PostgreSQL and create a DB
  • Inside WSL:
    sudo apt -y install postgresql
    sudo systemctl enable –now postgresql
    createdb nodeapp_dev
    psql -d nodeapp_dev -c “create table healthcheck(id serial primary key, ts timestamptz default now());”
  1. App configuration
  • In your Node.js app, set DATABASE_URL:
    DATABASE_URL=postgres://$USER@localhost:5432/nodeapp_dev
  • Test a query:
    node -e “const {Client}=require(‘pg’);(async()=>{const c=new Client({connectionString:process.env.DATABASE_URL});await c.connect();const r=await c.query(‘select now()’);console.log(r.rows[0]);await c.end();})();”
  1. Performance notes
  • DB data lives inside WSL (fast).
  • Node.js source on Windows is okay for editing; for fastest builds, run npm install and builds inside WSL:
    cd /mnt/c/projects/nodeapp
    npm ci
    npm run build
  • If builds feel slow due to Windows path, clone repo under ~ in WSL and use the VS Code WSL extension to edit directly on Linux.
  1. Optional: Docker Compose for DB only
  • In WSL:
    mkdir -p ~/data/postgres
    Create docker-compose.yml with a postgres service and volume under ~/data/postgres.
    docker compose up -d
  • Update app DATABASE_URL accordingly.
  • Keep volume in Linux paths for performance.

Result: Fast local dev with Postgres reachable from Windows tools (localhost:5432), quick builds when executed in WSL, and durable, service-managed DB.

Conclusion

You can Run Databases in WSL2 (Postgres/MySQL/Mongo) Without Performance Regret by following three core principles: Keep data on the Linux side, give WSL the right amount of RAM/CPU via .wslconfig, and use modern WSL features (systemd, mirrored networking) so services run reliably and are reachable via localhost. Add a few sensible DB tunings and you’ll get native-like performance, simple connectivity, and a smooth workflow across Windows and Linux tools—without juggling full VMs or dual-booting.

FAQ

Should I store my database on C:\ or inside WSL’s filesystem?

Store it inside WSL’s Linux filesystem (the distro’s ext4.vhdx), not under /mnt/c. Database workloads suffer on NTFS via the WSL 9P layer. Keep data under /var/lib/… or /srv/… inside WSL.

Do I need Docker Desktop, or can I run Docker directly in WSL?

Both work. Docker Desktop with WSL integration is easiest for most. If you run Docker Engine directly in WSL, keep volumes in Linux paths and expose ports normally. Avoid Windows bind mounts for database data.

Why can’t Windows connect to my WSL database on localhost?

You may be using older networking. Enable networkingMode=mirrored and localhostForwarding=true in .wslconfig and wsl –shutdown. Alternatively, use netsh portproxy to forward ports from Windows to the WSL IP.

How much memory should I allocate to WSL2?

For a single DB, 4–8 GB is comfortable. For multiple DBs/containers, 8–16 GB. Set memory in .wslconfig and tune DB caches to fit within that cap. Avoid huge swap files in dev.

How do I shrink the ext4.vhdx when it grows?

Clean caches (apt clean; journalctl vacuum), shut down WSL (wsl –shutdown), then run Optimize-VHD -Mode Full on the ext4.vhdx (requires Hyper-V PowerShell). Export/import via wsl –export / –import also re-compacts.

You’ve got this—set it up once, and WSL2 becomes a fast, reliable home for your dev databases.

About the author

Jonathan Dudamel

Jonathan Dudamel

I'm Jonathan Dudamel, an experienced IT specialist and network engineer passionate about all things Windows. I have deep expertise in Microsoft project management, virtualization (VMware ESXi and Hyper-V), and Microsoft’s hybrid platform. I'm also skilled with Microsoft O365, Azure ADDS, and Windows Server environments from 2003 through 2022.

My strengths include Microsoft network infrastructure, VMware platforms, CMMS, ERP systems, and server administration (2016/2022).