Mac mouse acceleration: turning it off so it sticks
The advice you find everywhere is a defaults write plus a logout. That moves one of two layers — and on macOS 26 the two disagree: the live pointer parameter read 0.6875 while the preference read 3. That is why acceleration comes back.
Two layers, and they do not have to agree
There is a live value that the system is using right now, and a persisted preference that gets restored at login. They are separate stores. Writing the preference alone means your change lands at the next login — until then, whatever holds the live value wins.
This is not a theory. Measured on macOS 26, with the Tracking Speed slider in the middle:
live HIDPointerAcceleration 0.6875
pref defaults read -g com.apple.mouse.scaling 3
live HIDMouseAcceleration (generic key) 196608 = 3.0 in 16.16 fixed point
pref defaults read -g com.apple.scrollwheel.scaling 0.3125
live HIDScrollAcceleration (generic key) 20480 = 0.3125
Two different numbers for the same slider, because they are two different things. The generic key is the one that matches the preference exactly.
The API name that half the internet uses does not exist
Plenty of guides — and, in our case, an actual work brief — name IOHIDSetPointerAcceleration. That symbol does not exist on any shipping macOS: it is missing from the SDK headers, absent from the .tbd stubs, and dlsym on the loaded IOKit image returns NULL.
What does exist, declared in <IOKit/hidsystem/IOHIDLib.h>, is a different set:
IOHIDSetMouseAcceleration/IOHIDGetMouseAcceleration→HIDPointerAccelerationIOHIDSetScrollAcceleration/IOHIDGetScrollAcceleration→HIDScrollAccelerationIOHIDSetAccelerationWithKey/IOHIDCopyCFTypeParameter/IOHIDSetCFTypeParameter
Those first four are marked deprecated as of 10.12 but still answer — and, crucially, none of them is the Tracking Speed slider. They are a different parameter that happens to live next door.
So what actually works
The live path for a tracking-speed control is the generic pair — IOHIDCopyCFTypeParameter and IOHIDSetCFTypeParameter — with the keys HIDMouseAcceleration and HIDScrollAcceleration. Both are public and neither is deprecated.
Measured behaviour: writing 2.0 and reading it back returned 2.0; restoring 3.0 read back 3.0. The write takes effect immediately and is reversible.
Because the preference is what survives a reboot, a tool has to write both: the preference for after the next login, the parameter for right now.
Two more details worth knowing: HID parameters are 16.16 fixed point, so 3.0 is stored as 196608; and -1 is the documented sentinel that means "disable pointer acceleration" rather than "very slow".
Scrolling is a separate axis
Turning off mouse acceleration does nothing for the wheel. Scroll acceleration lives in its own parameter — HIDScrollAcceleration, twin to com.apple.scrollwheel.scaling — which is why a page about "mouse acceleration" can leave you with a pointer that feels right and a wheel that still leaps.
How to check what is actually in force
Do not trust a success message; read the value back. Open the parameter port on the IOHIDSystem service, copy the key, and compare it with the preference. If the two disagree, the layer you wrote is not the layer that is deciding.
There is also a per-service property, HIDUseLinearScalingMouseAcceleration, which Apple’s own header says WindowServer sets for linear tracking. It can be set on the pointer services, but the public client may be refused — so treat it as best effort, not as the mechanism.
Honest limits
This is a system-wide input parameter. Applications that read raw HID, and games that do their own look handling, can bypass acceleration entirely and will not be affected either way. And nothing here changes how a trackpad behaves, because a trackpad is not reporting through the same path.
Related
Dimming on a schedule walks the screen to black · How do I change the brightness of an external display? · All guides · Mouse-wheel scrolling feels jerky · DDC/CI not responding · Which app should you use?