Check why the listener failed before changing the port

When Clash reports that port 7890 is already in use, first identify the process listening on it. Then decide whether to quit a duplicate instance or use a different listening port. Changing only the number in your system proxy settings does not change where the core listens. Changing only the config file without updating the system proxy leaves your browser connecting to the old port.

This guide starts with the local proxy address 127.0.0.1:7890 and uses 17890 as an example replacement. Port 17890 is not guaranteed to be available, so check it before use. Default ports can vary across Clash, Clash Meta (now called mihomo), and their GUI clients. Check the active configuration and startup logs to confirm which port is in use.

Distinguish between log errors

Log message or symptomCheck first
address already in useAn existing listener, a duplicate core instance, or multiple inbound listeners configured to use the same address and port.
Only one usage of each socket addressA common address-in-use error on Windows. First check local listening ports and their PIDs.
permission denied or access permissionsPermissions, security software, or a system-excluded port range may be involved; don't assume another app is using the port.
The browser reports that the proxy connection failedCheck the proxy address and whether the core is running. This symptom alone does not prove there is a port conflict.

Open the client logs and note the address, port, and protocol reported in the error. If the log points to 9090, check the control interface rather than changing 7890. If mixed-port is not enabled, investigate the active port or socks-port instead.

Windows: Find the process using netstat

Start by checking TCP listeners in a terminal. Open PowerShell or Command Prompt and run the command below. If the process details are incomplete, try again with administrator privileges.

netstat -ano -p tcp | findstr ":7890"

Look for entries where the “Local Address” ends in :7890 and the state is LISTENING. Don't mistake 7890 in “Foreign Address” or a TIME_WAIT connection for a listening service. This is an example of the output format, not a report from your device:

  TCP    127.0.0.1:7890    0.0.0.0:0    LISTENING    6420

The last column, 6420, is an example process ID. Replace it with the actual PID, then look up the process name:

tasklist /FI "PID eq 6420"

Filter by local port in PowerShell

If filtering the output as text returns too many results, use the command below instead. No results usually means no TCP listener was found at the time of the query. If the command returns a permissions or other error, resolve that first; you can't conclude the port is free.

Get-NetTCPConnection -LocalPort 7890 -State Listen -ErrorAction SilentlyContinue |
  Select-Object LocalAddress, LocalPort, OwningProcess

Get-Process -Id 6420 |
  Select-Object Id, ProcessName, Path
  1. If the process belongs to another Clash client, quit it from its tray menu and make sure its background core has stopped too.
  2. If it's an old core from the same client, quit the client and check whether service mode is still running. Stop the service using the client's service management controls to avoid repeatedly starting more instances.
  3. If the process is a development service or another proxy you need to keep running, leave it on its current port and choose a different available port for Clash.

macOS and Linux: Check listeners with lsof

On macOS, run lsof in Terminal. On Linux, use ss if lsof isn't installed. These commands check TCP listeners only, a useful first step when investigating the endpoint your browser uses for HTTP proxy connections.

sudo lsof -nP -iTCP:7890 -sTCP:LISTEN

-nP prevents addresses and ports from being translated into names. In the output, COMMAND is the process name, PID is the process ID, and NAME is the listening address. You can also inspect the full startup command to tell a core launched by a desktop client from a manually started service:

ps -p 6420 -o pid,ppid,command

You can also run this on Linux:

sudo ss -ltnp 'sport = :7890'

127.0.0.1:7890 indicates an IPv4 loopback listener; 0.0.0.0:7890 listens on all IPv4 addresses. A wildcard listener may conflict with a loopback listener on the same port. If you see [::]:7890, consider the system's IPv6 dual-stack behavior too. Don't rule out a conflict just because the address isn't IPv4.

Check UDP if needed

TCP and UDP use separate port spaces. UDP port 7890 being in use doesn't necessarily prevent a TCP listener on 7890 from starting. If the relevant UDP inbound is enabled, continue investigating based on the logs.

# macOS / Linux with lsof installed
sudo lsof -nP -iUDP:7890

# Linux
sudo ss -lunp 'sport = :7890'

Once you identify which service owns the process, stop it through its application or service manager whenever possible. If a service manager automatically restarts it, terminating only the child process may cause it to start again and reclaim the port.

Option 1: Change the port in the client settings

GUI clients often generate their runtime configuration at startup. For these clients, change the port in the settings UI rather than editing a temporary generated file. Menu names vary by client and version; look under “Settings” for “Port,” “Proxy Port,” or “Mixed Port.”

  1. First check whether 17890 is available using the commands above. Replace 7890 in the query with 17890.
  2. Note the current port and whether the system proxy is enabled. If the client keeps failing to start, temporarily turn off the system proxy to prevent apps from connecting to an unavailable endpoint.
  3. Open the client's “Settings” and find “Mixed Port” or a field labeled mixed-port. Set it to 17890. Don't change “External Controller,” “API,” or “Controller Port” by mistake.
  4. Save the settings, then reload the configuration or restart the core as prompted. Closing the settings window alone may not apply the change.
  5. Check the logs and listening ports to confirm the target core is listening on 17890, then re-enable the system proxy.

If the client shows separate “HTTP Port” and “SOCKS Port” fields, first confirm whether mixed port is enabled. Don't set all three fields to 17890; they aren't interchangeable labels for the same setting. If you're unsure what a field does, start with the configuration reference.

Option 2: Change mixed-port in config.yaml

If you run the core directly or explicitly use a local config, you can edit the YAML file that's actually loaded. Check the startup arguments or the config path shown in the client to identify the active file. A file named config.yaml isn't necessarily the one in use.

This snippet shows top-level fields for local use. Merge it into your existing config and keep your proxies, proxy groups, and rules. It isn't a complete config file you can use to replace a subscription.

mixed-port: 17890
allow-lan: false
mode: rule
log-level: info
  • mixed-port: A single listener accepts both HTTP proxy and SOCKS proxy connections. Applications must still use the correct proxy protocol.
  • allow-lan: false: Suitable for local-only use. Don't enable LAN access just to fix a local port conflict.
  • mode: rule: Keeps rule-based routing enabled. Changing the inbound port doesn't require changing the routing mode.
  • log-level: info: Makes startup messages easier to inspect. Restore the previous log level when troubleshooting is complete.

Check for duplicate keys and other inbound listeners

Place these fields at the YAML top level, using spaces for indentation. Don't put them under proxies or proxy-groups. Don't define mixed-port more than once at the same level. Parsers may handle duplicate keys differently, so don't rely on the last value overriding the first.

Also search for existing port, socks-port, and other inbound listener settings. Don't configure port: 17890 and mixed-port: 17890 to bind the same TCP address at once. Keep separate inbound listeners only if your application needs them.

Validate the config, then reload

When running mihomo directly, use the core's config test option to check the syntax. This example assumes the config file in the current directory is the one used at runtime. If the actual path is different, use that path instead.

mihomo -t -f ./config.yaml

A successful config test doesn't mean the listener has started. After saving, reload or restart the core and check the startup logs. Subscription-managed files may be overwritten during an update; use the client's supported persistent override method or manage the port through its global settings.

Update the system proxy and app proxy settings

After changing the core to port 17890, check every proxy setting that still points to 7890. System proxy settings, browser extensions, terminal environment variables, and developer tools each store their own values and usually don't update together.

Where to checkValue to verify
Windows 11“Settings” → “Network & Internet” → “Proxy” → “Manual proxy setup” → “Use a proxy server.” Set the address to 127.0.0.1 and the port to 17890.
macOS“System Settings” → “Network” → select the current network connection → “Details” → “Proxies.” Check Web Proxy, Secure Web Proxy, and SOCKS Proxy if enabled.
Browser proxy extensionUpdate the server port in the active profile and make sure it no longer uses 7890.
Terminal and developer toolsCheck HTTP_PROXY, HTTPS_PROXY, and ALL_PROXY, as well as separate proxy settings in Git, package managers, and IDEs.

If you use the client's “System Proxy” toggle, turn it off and back on after the new port is active, then verify the settings in your operating system. On macOS, “Secure Web Proxy” is the proxy setting for HTTPS websites; the name doesn't mean the local proxy endpoint itself must use TLS.

If your terminal uses environment variables, update them in the current macOS or Linux shell:

export HTTP_PROXY=http://127.0.0.1:17890
export HTTPS_PROXY=http://127.0.0.1:17890
export ALL_PROXY=socks5h://127.0.0.1:17890

Here, HTTPS_PROXY still uses http://, which means the connection is made through a local HTTP proxy. In tools that support it, socks5h means the proxy resolves the destination hostname. These commands affect only the current shell and its child processes. They don't persist the settings, and not all tools read these variables.

Verify the fix and investigate recurring conflicts

After troubleshooting, confirm at least three things: the new port is listening, the expected core owns the listener, and apps can send requests through it. Use the commands above to check port 17890, then make a request with an explicitly specified proxy to avoid interference from system proxy settings or environment variables.

# macOS / Linux
curl -I --proxy http://127.0.0.1:17890 --connect-timeout 5 --max-time 15 https://example.com/

# Windows PowerShell: call curl.exe explicitly
curl.exe -I --proxy http://127.0.0.1:17890 --connect-timeout 5 --max-time 15 https://example.com/

The 5-second value is the connection timeout; 15 seconds is the total request time limit. Neither is a speed test result. If you get Connection refused, first check the listening address and core status. If the proxy accepts the connection but the request later times out, check the matched rules, outbound node, and DNS logs. An HTTP response only confirms that this request reached the proxy endpoint; it doesn't prove all traffic is being proxied as expected.

Port is free, but the client still won't start

  • Windows excluded port ranges: If the log reports an access-permission error and no process is listening, run the command below to inspect excluded port ranges. Choose a port outside those ranges; don't delete system exclusions to work around the issue.
  • Old process restarts automatically: Check system services, startup apps, and whether two GUI clients are running at the same time.
  • Wrong config file edited: Check the active config path, startup arguments, and client override settings, then compare the logs after reloading.
  • Different virtualization boundaries: Docker, WSL, and the host may use separate network namespaces. Check on the side that actually binds the port; a listener inside a container doesn't guarantee the host port mapping is working.
netsh interface ipv4 show excludedportrange protocol=tcp
netsh interface ipv6 show excludedportrange protocol=tcp

Do I still need to change the system proxy when TUN is enabled?

TUN uses a virtual network adapter and routes to capture traffic; it doesn't work by having apps connect to port 7890. Even if TUN is working, the mixed port enabled in the config may fail to bind separately. Conversely, a working mixed-port listener doesn't prove that TUN routing and DNS are working. Troubleshoot these two traffic-capture paths separately, and don't use “the browser can still open websites” as a substitute for checking the listener.

Restart the client once more and confirm the port is still set to 17890. Test the config again after a subscription update if needed. If you must switch back to 7890, first make sure the process using it has stopped, then restore the system proxy and app proxy settings too. Keeping a record of the ports before and after troubleshooting can save repeated checks the next time you switch clients.