First, identify which listening port triggered the error

A port-in-use error when Clash starts usually occurs while the core is creating a local listener. The log message bind: address already in use means the address and port can’t be bound as configured. On Windows, you may also see Only one usage of each socket address. This is unrelated to expired subscriptions or unreachable nodes, so switching nodes is unlikely to help.

mixed-port accepts both HTTP and SOCKS proxy connections on the same port. This guide uses 7890 as the old port and 17890 as the new one. Both are examples: your machine may not use 7890, and 17890 may already be occupied. Start by opening the client log and noting the address, port, and protocol in the error.

FieldPurposeWhat to do
mixed-portCombined HTTP and SOCKS proxy listenerUpdate the system proxy and app proxy after changing it
port / socks-portSeparate HTTP or SOCKS listenerCheck for duplicate settings with the combined listener
external-controllerControl interface used by the client to connect to the coreAdjust it alongside the client’s control interface settings
dns.listenAddress used by the core’s DNS listenerCheck the DNS port shown in the log separately

Windows: Find the process using 7890 and what launched it

Find the listening PID with PowerShell

Open PowerShell and run the query below. OwningProcess is the process ID using the port, not the program name. If access is denied, reopen the terminal as an administrator. Don’t terminate an unknown system process just for convenience.

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

Suppose the query returns PID 1234. Use it to check the process name, executable path, and startup command. The number is only an example; replace it with the PID returned by the previous command.

Get-Process -Id 1234 |
  Select-Object Id, ProcessName, Path

Get-CimInstance Win32_Process -Filter "ProcessId = 1234" |
  Select-Object ProcessId, ExecutablePath, CommandLine

The path and startup arguments can help you distinguish between a separate core launched by another client and a background service still running for the same client. Even if both processes are named mihomo.exe, they may be in different installation folders. Closing the window from the taskbar doesn’t necessarily stop the process. Exit the relevant client from its system tray menu, then check the port again.

Cross-check with netstat

netstat -ano -p tcp | findstr ":7890"
tasklist /FI "PID eq 1234"

findstr is only a text filter; it may also match a remote port or another port containing the same digits. Check that the “Local Address” column actually ends in :7890 and that the state is LISTENING. An ESTABLISHED connection alone does not prove that a local listener is using port 7890.

  • 127.0.0.1:7890: listening on the IPv4 loopback address.
  • 0.0.0.0:7890: listening on all IPv4 interfaces; this may conflict with a binding to the loopback address.
  • [::]:7890: listening on all IPv6 interfaces. Whether this also affects IPv4 depends on the socket settings.

If the log specifically reports a UDP bind failure, check UDP endpoints. UDP has no TCP LISTENING state, so don’t use a check that only filters for TCP listeners.

Get-NetUDPEndpoint -LocalPort 7890 |
  Select-Object LocalAddress, LocalPort, OwningProcess

macOS and Linux: Check listeners and background services

macOS: Use lsof

Run the command below in Terminal. -nP keeps addresses and ports numeric to avoid name-resolution noise; -sTCP:LISTEN shows listening sockets only. If you don’t have sufficient permissions or the results look incomplete, add sudo before the command.

lsof -nP -iTCP:7890 -sTCP:LISTEN
ps -p 1234 -o pid,ppid,command

Check COMMAND, PID, and the full startup command, then exit the client normally from its menu. If the process immediately reappears, it may be managed by a login item, a client background component, or a service manager. Disable the relevant startup source before stopping the process; repeatedly force-quitting it may just cause the supervisor to restart the core.

Linux: Use ss

sudo ss -ltnp 'sport = :7890'
sudo ss -lunp 'sport = :7890'
ps -p 1234 -o pid,ppid,args

The first command checks TCP listeners; the second checks UDP bindings. ss is usually included in the iproute2 package. If it isn’t installed, use lsof if available. Administrator privileges may be required to show process details.

If the core is started by systemd, check the actual service unit and its ExecStart command. Closing the desktop client may not stop the service. Also check Docker port publishing: a container may be using port 7890 on the host, so don’t limit your search to processes started by the current user. Always identify what owns the port, then stop it through the manager that started it.

Free the old port or change mixed-port

You don’t need to terminate a process as soon as you find it. First decide whether it needs to keep running. If it’s an old client or a duplicate core instance, exit the extra instance and keep one running. If another service in use owns the port, changing Clash’s proxy listener is usually better than interrupting that service.

  1. Note the current port, system proxy address, and any proxy addresses configured separately in apps.
  2. Check the candidate port 17890 using the same method as for 7890.
  3. Confirm which client and core instance you intend to keep, so you don’t end up changing two different configurations.
  4. Change the configuration source that’s actually in use, then reload or restart the core.
  5. Verify the new listener, then update the port used by the system and apps.

Change mixed-port in YAML or client settings

If you manage the config file directly

Back up the config first, then find and edit the existing top-level mixed-port field in the YAML. Don’t append a second field with the same name at the end of the file. The snippet below shows only proxy listener settings; merge it into the existing full config and keep your current nodes, proxy groups, DNS, and rules.

# Merge into your existing config; this is not a complete subscription file
mixed-port: 17890
allow-lan: false
bind-address: "127.0.0.1"

This example is for local use only. If you previously shared the proxy over your LAN, don’t copy these access settings without checking the bind address, authentication, and firewall rules separately. Don’t enable LAN access just to fix a local port conflict; it won’t free the port that’s already in use.

Also check for port: 17890 or socks-port: 17890. Separate listeners and the mixed listener shouldn’t bind to the same address and TCP port. If you use only the mixed listener, remove the separate port field once you’ve confirmed the client doesn’t rely on it, or set it to 0 if supported by your core configuration.

If you run mihomo manually, you can test the config in a terminal. This example assumes the file in the current directory is named config.yaml and the core command is mihomo.

mihomo -t -f config.yaml

-t tests the configuration; it doesn’t confirm that a proxy listener started successfully. After the test, load the file through your usual startup method and check the startup log. A client may download or generate a runtime config that differs from this file, so testing an unused copy isn’t enough.

If a graphical client manages the config

First, check the client settings for a field named “Mixed Port,” “mixed port,” or “proxy port.” Menu names vary by client and version; these are labels to help you identify the setting, not a universal navigation path. Save the change and reload the core as required by the client. Editing the subscription itself may not override a port setting generated by the client.

  • Port setting available in the interface: Change it there first, then check the runtime log for the new port.
  • No matching setting in the interface: Check whether the client supports local overrides or merged configs, then set the top-level mixed-port there.
  • Port reverts to 7890 after a subscription update: Check whether you edited a subscription cache that gets overwritten. Move the change to a persistent configuration option supported by the client.
  • Still listening on the old port after saving: Check which config is selected, the runtime file path, and client setting precedence, then restart the correct core instance.

You can turn off the system proxy before making changes to prevent it from sending traffic to a listener that’s temporarily unavailable. Turn it back on after the new port starts successfully. If the client updates the system proxy automatically, check the system settings to confirm the final value rather than assuming the change was applied.

Update the system proxy, browser, and command-line tools

If the core switches to 17890 while the system still uses 7890, this is a common reason the port conflict is gone but web pages still won’t load. For a local HTTP proxy, use 127.0.0.1:17890. The mixed port also accepts SOCKS connections, but use the proxy type and format required by each app.

LocationWhere to checkExample value
Windows 11Settings → Network & Internet → Proxy → Manual proxy setup → EditAddress: 127.0.0.1; port: 17890
Recent macOS versionsSystem Settings → Network → Details for the current network → ProxiesCheck the address and port for both the web proxy and secure web proxy
Firefox manual proxySettings → General → Network Settings → SettingsUse the system proxy or update the manual proxy port
Command-line toolsCheck HTTP_PROXY, HTTPS_PROXY, ALL_PROXY, and the tool’s own settingsSet the new port; open a new terminal if needed

Linux desktop environments don’t have one standard system proxy menu; GNOME, KDE, and individual apps may each manage their own settings. Windows system proxy settings and the WinHTTP proxy are separate. Use netsh winhttp show proxy to check the latter; resetting WinHTTP is not a general fix for every browser problem.

The PowerShell commands below update HTTP proxy environment variables for the current session only; they won’t change settings for all apps. When HTTPS traffic uses a local HTTP proxy to create a tunnel, the proxy address can still use http://. The local listener doesn’t need TLS just because the destination uses HTTPS.

$env:HTTP_PROXY = "http://127.0.0.1:17890"
$env:HTTPS_PROXY = "http://127.0.0.1:17890"

Temporarily set the variables in a macOS or Linux shell:

export http_proxy=http://127.0.0.1:17890
export https_proxy=http://127.0.0.1:17890

If you previously set ALL_PROXY, Git’s http.proxy, or a proxy in your editor, check those settings separately. Tools handle environment variables differently, and already-running apps usually won’t pick up updated values automatically.

Verify with a listener check, a request, and a restart

Check the local listener before testing a request

Run the port check from earlier again, replacing 7890 with 17890, and confirm the listener belongs to the core you intend to use. Then send a request with an explicit proxy argument to avoid uncertainty about whether the system proxy settings took effect. On Windows, use curl.exe to avoid PowerShell environments where an alias with the same name may affect how arguments are interpreted.

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

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

The 5-second value is the connection timeout, and 15 seconds is the total request timeout; neither is a performance measurement. --noproxy "" clears the proxy bypass list for this request. Results still depend on the node, rules, DNS, and the destination site’s availability.

  • Connection refused immediately: Check whether the new port is listening, the address is correct, and the core is still running.
  • Connected to the local listener, but the request timed out: Check the core log for node connection, rule matching, and DNS errors.
  • Explicit proxy request works, but the browser doesn’t: Check the browser’s separate proxy settings, the old system proxy port, and extension settings.
  • Command-line request works but doesn’t use the expected node: Check the active rules and policy selection; a successful request alone doesn’t prove traffic went through a proxy node.

Check again after restarting and updating the subscription

Exit and restart the client, then confirm it’s still listening on 17890. Update the subscription as usual and check that the port hasn’t reverted to 7890. If another process takes the port after a restart, check the other client’s startup items and background services instead of temporarily switching to a new port each time.

Evaluate TUN mode separately: TUN routes system traffic, but that doesn’t mean apps are using mixed-port. If pages load with TUN enabled, that doesn’t prove the old system proxy port has been fixed. Some clients may also fail to start certain features when the mixed listener conflicts. During verification, check the logs, local listener, and request path separately.