Skip to content

SOPs

Reset macOS Screen Sharing Remotely

Screen Sharing.app shows:

Connection Failed Screen Sharing is not permitted on “192.168.1.220”. Disable and re-enable Screen Sharing or Remote Management in System Settings before trying again.

But on the target Mac, the System Settings toggle is already on, the user is in the access list, and netstat shows *.5900 listening. Often there is even an ESTABLISHED socket from the failing client, which means the TCP handshake completed and the rejection happened at the macOS permission layer above it.

This usually follows a sleep/wake cycle, an OS update, or any event that changes user session state. screensharingd keeps running, but its in-memory permission cache has rotted.

Bootout and bootstrap the daemon. This is the command-line equivalent of toggling the System Settings switch off and back on.

Terminal window
sudo launchctl bootout system /System/Library/LaunchDaemons/com.apple.screensharing.plist
sleep 2
sudo launchctl bootstrap system /System/Library/LaunchDaemons/com.apple.screensharing.plist

bootout may exit non-zero if the service is already in a partial state. That is fine — bootstrap reloads it from a known place either way.

Verify port 5900 is back to a clean listening state with no stale ESTABLISHED sockets:

Terminal window
lsof -iTCP:5900 -sTCP:LISTEN -n

Then reconnect with Screen Sharing.app. The “not permitted” dialog goes away.

The reason this SOP exists at all is that the obvious fix — walk over to the machine and flip the System Settings toggle — is the thing you cannot do when Screen Sharing is broken. You also cannot SSH in and sudo directly from a non-interactive shell because sudo needs a TTY for the password prompt (see Running sudo Over SSH).

The pattern that works: open a Terminal on the client (the Mac you are sitting at), have it ssh -t into the target (the Mac that needs the reset), and let sudo prompt for the password locally so you can type it.

If Claude is running on the broken machine itself and cannot pop a Terminal where you are, use run-terminal-over-ssh.sh — it scp’s a script to the client, runs it via Terminal do script, polls until the tab finishes, and closes the window so dead terminals do not pile up.

The script body looks like this:

#!/bin/bash
set -u
ssh -t studio 'sudo bash -c "
launchctl bootout system /System/Library/LaunchDaemons/com.apple.screensharing.plist 2>&1 || echo \"(bootout returned non-zero, often fine)\"
sleep 2
launchctl bootstrap system /System/Library/LaunchDaemons/com.apple.screensharing.plist 2>&1
sleep 1
lsof -iTCP:5900 -sTCP:LISTEN -n | head -5
"'
echo ""
echo "Press return to close this window."
read

Save to /tmp/fix-screensharing.sh, then on the server side:

Terminal window
bash ~/apps/cc/bin/run-terminal-over-ssh.sh mbp /tmp/fix-screensharing.sh

A Terminal window pops up on the client, prompts for the target’s sudo password, runs the bootout/bootstrap pair, prints the verification output, and closes itself when you press return.

Why Not Just AppleScript The System Settings Toggle

Section titled “Why Not Just AppleScript The System Settings Toggle”

tell application "System Events" to click ... requires Accessibility permission on the target, which a remote osascript session almost never has. It fails with (1002). The launchctl pair is what the toggle does under the hood anyway, so skip the UI dance.

sudo killall screensharingd does restart the process via launchd, but it does not flush the same caches that bootout does. In practice the “not permitted” state survives a plain kill and only clears with the bootout/bootstrap cycle.