ADB is one binary that wears three hats. Most "adb is being weird" reports come from misunderstanding which hat is misbehaving (the local CLI, the long-lived host server on port 5037, or the on-device adbd), or from two different adb binaries fighting over the same port. This skill grounds the mental model so the rest of the ADB skill set has a stable foundation.
When to use this skill
- The user sees
* daemon not running; starting now at tcp:5037 *and assumes it is an error. - The user sees
adb server version (XX) doesn't match this client (YY); killing...after Studio updates its bundled platform-tools. - The user wants to enable verbose ADB logging (
ADB_TRACE) or set up a CI runner with a preinstalled vendor key. - The user asks why deleting
~/.android/adbkeybreaks every other paired device. - The user is debugging port 5037 collisions, multiple adb installs, or libusb-related transport failures on Linux.
When NOT to use this skill
- The user is troubleshooting a specific connected device (USB authorization,
unauthorized,no permissions) — use../../devices/connecting-to-devices/SKILL.md. - The user is setting up wireless / Wi-Fi ADB — use
../../devices/connecting-over-wifi/SKILL.md. - The user is running
adb shell am instrumentfor tests — use../../tests/running-instrumented-tests-via-adb/SKILL.md.
Prerequisites
- Android SDK Platform-Tools installed (path resolution rules below).
- Shell access to a workstation with
adbon$PATH. - For diagnostic flows: write access to
$TMPDIR(macOS/Linux) or%TEMP%(Windows).
Workflow
-
1. Internalize the three-piece model. From developer.android.com/tools/adb (Overview):
- Client (
adbCLI) — invoked from the terminal. Serializes commands and ships them to the server over a local TCP socket. - Server (
adb-server) — host-side background process. Multiplexes commands from many clients, tracks connected transports, forwards traffic toadbd. Binds TCP port 5037 onlocalhostby default. - Daemon (
adbd) — runs on the device. Spawned byiniton userdebug/eng builds, and by the system on user builds. Receives commands from the host server over USB or TCP and executes them in the device's userspace.
- Client (
-
2. Recognize the implicit
start-serverprint. The firstadbcommand on a fresh shell emits:* daemon not running; starting now at tcp:5037 * daemon started successfullyThis is informational, not an error —
adbauto-starts the server when none is running. Skipping over this fact wastes hours of debugging. -
3. Use the lifecycle commands surgically:
Command Effect adb start-serverEnsures a server is running on port 5037. If a compatible server is already running, it's a no-op (idempotent). If a different process is bound to 5037 (or an older incompatible adb server), start-serverfails — see the port-collision pattern below.adb kill-serverTerminates the local server. The next adbcommand respawns it.adb reconnect"Kick connection from host side to force reconnect." Useful for a stuck USB transport. adb reconnect device"Kick connection from device side." Asks adbdto drop and re-handshake.adb reconnect offline"Reset offline/unauthorized devices to force reconnect." Targets only the misbehaving transports. adb -P PORT ...Override the server port (default 5037). Same as ANDROID_ADB_SERVER_PORT.Stuck-transport recovery recipe:
adb reconnect offline # if that fails: adb kill-server && adb start-server && adb devices -
4. Resolve the binary path explicitly.
adbships in Android SDK Platform-Tools (android_sdk/platform-tools/). Check what is actually loaded:adb --version which -a adb # find shadowed copiesSample
adb --versionoutput decoded:Android Debug Bridge version 1.0.41 # wire-protocol version (stable for years) Version 35.0.2-12147458 # platform-tools release + Google build number Installed as /opt/homebrew/bin/adb # the actual file the OS resolved Running on Darwin 24.6.0 (arm64)The wire-protocol number is what matters for cross-compatibility: client and server must agree, or the first command kills the older server with
adb server version (XX) doesn't match this client (YY); killing.... -
5. Pick ONE canonical adb when Android Studio is involved. Studio bundles and auto-updates its own
platform-tools/. If a system / Homebrew adb is also on$PATH, three failure modes appear:- Version skew — first command issued by either kills the running server.
- Two competing servers ping-ponging port 5037.
- Different default backends (libusb vs. native) producing inconsistent device enumeration.
Resolution rule of thumb:
export PATH="$ANDROID_HOME/platform-tools:$PATH"so CLI and Studio agree, thenadb kill-serveronce.
-
6. Know the environment variables (verbatim, from
adb help):Variable Purpose ADB_TRACEComma/space-separated debug categories. Tokens: all,adb,sockets,packets,rwx,usb,sync,sysdeps,transport,jdwp,services,auth,fdevent,shell,incremental.ADB_VENDOR_KEYSColon-separated paths to RSA key files/dirs. Use on CI to skip the "Allow USB debugging?" prompt. ANDROID_SERIALDefault device serial (equivalent to -s). Overridden by-s.ANDROID_ADB_SERVER_PORTOverride the server port (default 5037). Equivalent to -P PORT.ADB_LOCAL_TRANSPORT_MAX_PORTHighest odd port scanned for emulators. Default 5585(16 emulators).ADB_MDNS_AUTO_CONNECTCSV of mDNS service types eligible for auto-connect. Default: adb-tls-connect.ADB_MDNS_OPENSCREEN1/0. Force the Openscreen mDNS backend. Default Openscreen on Linux/Windows from ADB v34+ — the public doc lags.ADB_LIBUSB1/0. Force the libusb USB backend.ADB_BURST_MODE1/0. Pipeline packets without ACK. Experimental, ADB 36.0.0+.Diagnostic recipe with maximum verbosity:
ADB_TRACE=all adb devices -l 2>~/adb-trace.logCI runner with a preinstalled key and custom port:
export ADB_VENDOR_KEYS=/etc/adb/ci-key export ANDROID_ADB_SERVER_PORT=5038 export ADB_LOCAL_TRANSPORT_MAX_PORT=5617 adb start-server -
7. Find the server log when something is wrong. The server keeps a persistent log distinct from per-command
ADB_TRACEoutput and fromlogcat:OS Path macOS $TMPDIR/adb.$UID.log(e.g./var/folders/.../T/adb.501.log)Linux $TMPDIR/adb.$UID.log(e.g./tmp/adb.1000.log)Windows %TEMP%\adb.logUseful flow: adb kill-server ADB_TRACE=adb,transport,auth adb start-server adb devices -l ls -lh "$TMPDIR/adb.$UID.log" -
8. Treat
~/.android/as load-bearing. RSA keypair:~/.android/adbkey(private),~/.android/adbkey.pub(public). Generated on firstadbinvocation. Every accepted "Allow USB debugging?" dialog appends this public key to/data/misc/adb/adb_keyson the device. Wiping the local key invalidates every device the user previously authorized — see the WRONG/RIGHT pair below. -
9. Accept the libusb v36 regression on Linux as background context. ADB v36.0.0 (Apr 2025) shipped a rewritten libusb backend with hot-plug. ADB v36.0.2 (Sep 2025) reverted libusb as the Linux default because of instability. CI runners pinned to specific platform-tools versions need to know which side of that revert they sit on; force the backend explicitly with
ADB_LIBUSB=0or=1if reproducibility matters.
Patterns
Pattern: WRONG vs RIGHT — recovering from unauthorized or offline device
# WRONG
rm -rf ~/.android/adbkey ~/.android/adbkey.pub
adb kill-server
adb start-server
# WRONG because: this rotates the host RSA keypair. Every previously authorized
# device now sees an unknown public key and re-prompts the "Allow USB debugging?"
# dialog. CI runners and headless test farms break silently because nobody is
# there to tap "Allow". Worse, the key on /data/misc/adb/adb_keys for the old
# pubkey lingers as orphan data.
# RIGHT
adb reconnect offline # try a targeted reset first
adb devices # confirm the state changed
# if still offline:
adb kill-server && adb start-server
# if still unauthorized: unlock the device, re-tap "Allow USB debugging?"
The keypair only needs regenerating when it is genuinely lost or corrupted; in that case, adb keygen ~/.android/adbkey rebuilds it deliberately and the user accepts that every device must re-authorize.
Pattern: WRONG vs RIGHT — two competing adb installs
# WRONG
brew install android-platform-tools # installs adb to /opt/homebrew/bin
# Studio also auto-updates ~/Library/Android/sdk/platform-tools/adb
# PATH puts /opt/homebrew/bin first.
# Studio's "Run" button uses ~/Library/Android/sdk/platform-tools/adb (different version).
# First command issued by either side prints:
# adb server version (41) doesn't match this client (40); killing...
# WRONG because: every Run-button invocation kills the server you started,
# yanks transports out from under Logcat, and reissues "daemon not running".
# RIGHT
# Pick one canonical adb. Easiest: prefer Studio's bundled platform-tools.
export ANDROID_HOME="$HOME/Library/Android/sdk"
export PATH="$ANDROID_HOME/platform-tools:$PATH"
adb kill-server # clear stale state once
adb --version # confirm path matches Studio's
Pattern: WRONG vs RIGHT — port 5037 already in use
# WRONG
# Some other tool (nc, a proxy, a stale adb-server zombie) is bound to 5037.
adb start-server # silently fails; subsequent adb devices hangs.
# RIGHT
lsof -nP -iTCP:5037 -sTCP:LISTEN # find the holder (macOS/Linux)
# kill the squatter, OR run a second adb server on a different port:
ANDROID_ADB_SERVER_PORT=5038 adb start-server
ANDROID_ADB_SERVER_PORT=5038 adb devices
Mandatory rules
- MUST treat
* daemon not running; starting now at tcp:5037 *as informational, not an error. - MUST keep ONE
adbbinary first on$PATH. Mixing Studio-bundled and system-installedadbof different versions causes server ping-pong. - MUST preserve
~/.android/adbkeyand~/.android/adbkey.pubacross machine moves; wiping them silently breaks every previously authorized device. - MUST NOT delete
~/.android/adbkey*as a "fix" forunauthorizedorofflinedevices — useadb reconnect offlinefirst. - MUST NOT run two
adbservers on port 5037 simultaneously. UseANDROID_ADB_SERVER_PORT(or-P PORT) for sharded CI. - PREFERRED: put
export PATH="$ANDROID_HOME/platform-tools:$PATH"in the shell profile so the CLI and Studio resolve the same binary. - PREFERRED: when reporting a transport bug, attach the server log from
$TMPDIR/adb.$UID.log(macOS/Linux) or%TEMP%\adb.log(Windows) plus anADB_TRACE=adb,transport,authreproduction.
Verification
-
adb --versionprints a single binary path;which -a adblists no shadowed copies. -
adb start-serveris idempotent — running it twice does not change anything. -
adb kill-server && adb start-server && adb devicesrecovers a stuck transport. -
~/.android/adbkeyand~/.android/adbkey.pubexist and are not world-readable (chmod 600 ~/.android/adbkey). -
ADB_TRACE=adb adb devices -lproduces verbose transport logs without errors. - If running multiple adb servers, each has a distinct
ANDROID_ADB_SERVER_PORTvalue andlsof -iTCP:5037shows exactly one (or zero) listeners. - Server log file exists at
$TMPDIR/adb.$UID.log(macOS/Linux) or%TEMP%\adb.log(Windows) and is recent.
References
- ADB user guide (architecture and lifecycle): https://developer.android.com/tools/adb
- Platform-tools release notes (version deltas, libusb default): https://developer.android.com/tools/releases/platform-tools
- AOSP
adbman page (canonical env-var reference): https://android.googlesource.com/platform/packages/modules/adb/+/refs/heads/main/docs/user/adb.1.md - Studio + AGP testing on the command line: https://developer.android.com/studio/test/command-line
- Source-of-truth research notes (CORPUS §I, A1 report):
tasks/research/A1-adb-architecture-devices.md— three-piece model, env-var table, libusb v36 revert, Openscreen-vs-Bonjour default flip in ADB v34+, server log paths, RSA keypair handling.docs/CORPUS.md§I.2 (three-piece architecture) and §I.10 (critical findings:force-stop≠pm clear, exit codes only with-w).
- Sibling skills:
- Connect a single device:
../../devices/connecting-to-devices/SKILL.md - Wireless ADB (Android 11+):
../../devices/connecting-over-wifi/SKILL.md - Install / manage apps:
../../apps/installing-and-managing-apps/SKILL.md - Run instrumented tests via
am instrument:../../tests/running-instrumented-tests-via-adb/SKILL.md
- Connect a single device:
- Cross-set neighbours:
- Configure JUnit4 on Android:
../../../jvm-tests/runner/configuring-junit4-on-android/SKILL.md - Run instrumented tests with
AndroidJUnit4:../../../instrumentation/runner/running-instrumented-tests-with-androidjunit4/SKILL.md - Source-set strategy:
../../../fundamentals/strategies/organizing-test-source-sets/SKILL.md
- Configure JUnit4 on Android: