
macOS: Serial Port Busy — Find What’s Holding `/dev/cu.*` and Free It
macOS: Serial Port Busy — Find What’s Holding /dev/cu.* and Free It
If you use serial console ports often, you’ll eventually hit the classic problem: the adapter shows up, the port is there, but your terminal refuses to open it. You’ll see errors like “Resource busy,” “Device is busy,” or it just fails to connect.
Most of the time nothing is “broken.” The port is already open in another process—sometimes it’s your own forgotten screen session, sometimes a GUI terminal app, sometimes a Python script that’s still running, or a background logger you started earlier.
This post shows a quick, calm way to figure out what’s holding the port, free it, and avoid the same issue next time.
If you do this kind of work regularly (especially across lots of devices), take a look at clideck.com. We’re building practical serial/console guides and tools for people who want things to work the same way every time—without wasting an evening on small but annoying problems.
Quick fix
- List ports and copy the one you’re using:
ls -1 /dev/cu.* | head
- See what process is holding the port (replace with your port name):
lsof /dev/cu.usbserial-0001
- If it’s
screen, close it cleanly:
screen -ls
screen -r <ID>
# then inside screen: Ctrl+A, then K, then y
- If the process is stuck, end it:
kill <PID>
If that doesn’t work:
kill -9 <PID>
- Confirm the port is free:
lsof /dev/cu.usbserial-0001
No output usually means you’re good.
Why this happens
On macOS, a serial port is a device file (like /dev/cu.* and /dev/tty.*). Once one process opens it, a second process typically can’t open the same port at the same time.
Common culprits:
- a forgotten
screensession (maybe in another Terminal window) - SecureCRT / CoolTerm / Serial / any GUI terminal app
- a Python script (pyserial) still running
- a background logging command you started and forgot about
Step 1: Make sure you’re opening the right port
On macOS, you usually want /dev/cu.*, not /dev/tty.*.
List them:
ls -1 /dev/cu.*
If you have multiple adapters plugged in, it’s easy to grab the wrong one. Always copy/paste the full device name.
Step 2: Identify what’s holding the port
The simplest check:
lsof /dev/cu.usbserial-0001
If you’re not sure which exact port name you need, you can scan all open serial devices:
lsof | grep -E '/dev/cu\.' | head -n 50
In the lsof output, pay attention to:
- COMMAND (what program it is)
- PID (the process ID you can kill)
- USER (useful if it’s not your session)
Step 3: The most common case — it’s screen
List active screen sessions
screen -ls
If you see entries like:
12345.tty.usbserial-0001(Attached)67890.tty.usbserial-0001(Detached)
…that’s usually your answer.
If the session is “Attached”
Sometimes it’s open in another window and you forgot. You can:
- go to that window and exit normally, or
- take control of the session:
screen -r <ID>
If it says it’s already attached, use:
screen -d -r <ID>
Close screen the right way so the port is released
Inside screen:
Ctrl+A, thenK, theny
Then confirm:
lsof /dev/cu.usbserial-0001
Step 4: If it’s not screen
You might see python, node, cu, minicom, CoolTerm, Serial, etc.
Try a normal stop first
kill <PID>
Wait a second, then re-check:
lsof /dev/cu.usbserial-0001
If it’s hung
kill -9 <PID>
That usually frees the port immediately.
Step 5: “I killed it, but the port is still busy”
This is less common, but it happens.
1) You’re checking the wrong port name
Double-check the exact device path.
2) There’s a second process holding it
Run the check again:
lsof /dev/cu.usbserial-0001
3) The USB chain is acting up (hub/dock/adapter)
Fast hardware fix:
- unplug/replug the adapter
- try a different USB port
- if you’re on a dock, try plugging directly into the Mac
After replugging, the device name can change, so re-list ports:
ls -1 /dev/cu.*
How to avoid this next time
1) If you use screen a lot, glance at sessions before connecting
screen -ls
It takes one second and often reveals the problem instantly.
2) Always exit screen cleanly
Closing the Terminal window isn’t the same as closing the port. Use Ctrl+A → K → y.
3) If you write scripts, close the port on errors
If you’re using Python/pyserial, make sure you close the port reliably (e.g., try/finally or a context manager). Otherwise a process can stay alive and keep the device locked.
Mini command cheat sheet
Who’s holding the port:
lsof /dev/cu.usbserial-0001
List screen sessions:
screen -ls
Take over an attached screen session:
screen -d -r <ID>
Stop a process:
kill <PID>
Force-stop:
kill -9 <PID>