The reliable way to turn Bluetooth on or off from the macOS command line in 2026 is blueutil, a small open-source CLI. Install it once, then a single command flips the radio:
brew install blueutil
blueutil -p 1 # Bluetooth ON
blueutil -p 0 # Bluetooth OFF
blueutil -p toggle # flip whatever state it is in now-p is short for --power; both forms work. With no value it prints the current state, so blueutil -p is your read command and blueutil -p 1 / -p 0 are the writes. Do not reach for sudo here: Bluetooth power is a per-user setting, and blueutil actively refuses to run as root unless you set BLUEUTIL_ALLOW_ROOT=1, so sudo blueutil -p 1 errors out rather than helping. Run it as your normal user.
The rest of this page is the detail behind that: reading the state in a script, listing and connecting paired devices, the macOS permission gotcha on recent versions, and why blueutil is the answer at all now that the old defaults tricks are dead.
Why blueutil and not a defaults one-liner
If you searched for this a few years ago you probably found a defaults write / blued recipe that poked the Bluetooth preference plist and restarted the daemon. That path no longer works. Apple moved Bluetooth state out of the old user-readable plist and locked down the controller daemon, so the defaults-and-restart hacks either silently do nothing or need a reboot to take effect. blueutil talks to the private Bluetooth framework directly, which is why it stays current while the plist tricks rotted. For toggling the radio from the terminal, it is the route that actually works today.
The trade-off is that blueutil is a third-party binary rather than something built in. It is open source, installs cleanly from Homebrew, and is widely used, so that is a small price for a command that reliably does the one thing you asked.
What macOS gives you built in
macOS ships exactly one useful Bluetooth command out of the box, and it is read-only: system_profiler SPBluetoothDataType. It dumps the controller details and every paired or connected device, the same data the Bluetooth pane of System Information shows:
system_profiler SPBluetoothDataTypeThat is fine for inspecting state in a script (each device entry carries a Connected: Yes/No line and an address you can grep for), but it cannot change anything. There is no built-in command that flips the radio cleanly. The old defaults write /Library/Preferences/com.apple.Bluetooth ControllerPowerState -int 0 plus sudo killall bluetoothd recipe still floats around, but on current macOS it is unreliable: it often needs a reboot to take, and on Apple Silicon it frequently does nothing at all. That gap, a built-in command that can read but not toggle, is exactly why blueutil exists.
Read the current state
With no value, -p prints 1 (on) or 0 (off). That is what you script against:
blueutil -p
# 1A toggle that flips the radio either way, without you having to know the starting state, is a one-liner. blueutil -p toggle does exactly this, and it is cleaner than the older grep-based trick:
# Preferred: blueutil knows how to toggle itself
blueutil -p toggle
# The older idiom, still works, reads the state then flips it:
blueutil -p | grep -q 1 && blueutil -p 0 || blueutil -p 1If you reach for this often, wrap it in a shell function in your ~/.zshrc. The te_ prefix keeps the helper out of the way of anything else named bt:
te_bt() {
case "$1" in
on) blueutil -p 1 ;;
off) blueutil -p 0 ;;
*) blueutil -p toggle ;;
esac
}Then te_bt on, te_bt off, or a bare te_bt to toggle.
List and manage paired devices
blueutil is not just a power switch. It can enumerate what your Mac knows about and connect to a specific device:
blueutil --paired # everything your Mac has paired with
blueutil --connected # only what is connected right nowEach line includes the device address (the xx-xx-xx-xx-xx-xx Bluetooth MAC). Feed that address to --connect or --disconnect to drive a single device, which is the useful bit when you want a script to grab your headphones without touching the menu bar:
blueutil --connect 00-11-22-33-44-55
blueutil --disconnect 00-11-22-33-44-55
blueutil --info 00-11-22-33-44-55 # connection + signal detail for one deviceThis is where the CLI earns its keep over the GUI: a login script that connects a specific keyboard, a hotkey that reconnects a flaky speaker, or a quick --info check on signal strength without opening System Settings.
When you actually reach for this
Two cases come up over and over. The first is scripting: a Keyboard Maestro macro, a cron job, or a shell alias that turns Bluetooth off when you dock at a wired setup and back on when you leave. The second is the stuck radio. When the menu-bar toggle stops responding (mouse frozen, headphones refusing to reconnect, the icon spinning forever), blueutil -p 0 && blueutil -p 1 cycles the radio from the keyboard without needing the pointer you just lost. That second one is the reason a lot of people install blueutil in the first place.
The permission gotcha on recent macOS
On recent macOS, especially Apple Silicon, the terminal app running blueutil may need to be granted Bluetooth access under System Settings, Privacy & Security, Bluetooth. The first power-toggle can prompt; a non-interactive script will fail silently until the terminal (Terminal, iTerm, or whatever you run it from) is checked in that list. Toggling can also be briefly flaky right after the Mac wakes from sleep, before the controller has fully come back. If blueutil -p 1 seems to do nothing, check that permission entry first.
FAQ
See also
- Take a photo with the Mac camera from the command line: same TCC-permission pattern, with the warm-up flag that stops you getting a black frame.
- Change the system volume from the macOS command line: the modern 0 to 100 volume form, mute, and reading the current level.
- Open apps, files, and URLs from the macOS command line: the
opencommand reference, including the zsh URL-quoting gotcha.
Sources
Authoritative references this article was fact-checked against.





