Excessive batter drain in macOS during sleep mode.

We are experiencing abnormal battery drain during sleep on several machines that installed our product. The affected devices appear to enter and exit sleep repeatedly every few seconds, even though the system logs show no new wake request reasons or changes in wake timers.

Symptoms:

  • Battery drops ~1% every ~15–20 minutes overnight.
  • pmset -g log shows repeated "Entering Sleep" and "Wake Requests" events every few seconds.
  • Wake requests remain unchanged between cycles and are scheduled far into the future (i.e. 20+ minutes later), yet the log lines keep repeating.

On healthy machines, the same wake request entries appear only once every 20–30 minutes as expected, with minimal battery drop during sleep (~1% in 9 hours).

What we've checked:

  • No user activity (system lid closed, device idle).
  • No significant pmset -g assertions; only powerd and bluetoothd are holding expected PreventUserIdleSystemSleep.
  • pmset -g on affected machines shows sleep set to 0, likely due to sleep prevented by powerd, bluetoothd.
  • No third-party daemons are holding assertions or logging excessive activity.

Sample Logs from Affected Machine:

2025-06-28 21:57:29 Sleep Entering Sleep state due to 'Maintenance Sleep':TCPKeepAlive=active Using Batt (Charge:76%) 3 secs    
2025-06-28 21:57:31 Wake Requests [process=mDNSResponder request=Maintenance deltaSecs=7198 wakeAt=2025-06-28 23:57:29 ...]
2025-06-28 21:57:38 Sleep Entering Sleep state due to 'Maintenance Sleep':TCPKeepAlive=active Using Batt (Charge:76%) 3 secs    
2025-06-28 21:57:40 Wake Requests [process=mDNSResponder request=Maintenance deltaSecs=7198 wakeAt=2025-06-28 23:57:38 ...]
2025-06-28 21:57:47 Sleep Entering Sleep state due to 'Maintenance Sleep':TCPKeepAlive=active Using Batt (Charge:75%) 3 secs    
2025-06-28 21:57:49 Wake Requests [process=mDNSResponder request=Maintenance deltaSecs=7198 wakeAt=2025-06-28 23:57:47 ...]

The only change in logs is the wakeAt timestamp being slightly updated . The wake requests themselves (process, type, deltaSecs) remain identical. Yet, the system keeps entering/exiting sleep every few seconds, which leads to power drain.

We would appreciate your help in identifying:

  • Why the sleep/wake cycles are repeating every few seconds on these machines.
  • Whether this behavior is expected under certain conditions or indicates a regression or misbehavior in power management.
  • How we can trace what exactly is triggering the repeated wake (e.g., a subsystem, implicit assertion, etc.).
  • Whether there are unified log predicates or private logging options to further trace the root cause (e.g., process holding IO or waking CPU without explicit assertion).

We can provide access to full logs, configuration profiles, and system diagnostics if needed.

Answered by DTS Engineer in 847233022

Reordering questions for clarity:

How can we trace what exactly is triggering the repeated wake (e.g., a subsystem, implicit assertion, etc.)?

mDNSResponder, which is the daemon which handles DNS resolution and, more importantly, manages Bonjour:

Wake Requests [process=mDNSResponder request=Maintenance...

Whether this behavior is expected under certain conditions or indicates a regression or misbehavior in power management.

The power management system itself isn't really at fault, as its job is to "do what it's told" and it's waking the system exactly as it was "told" to. Similarly, I don't think mDNSResponder itself is directly responsible*, as its role is large "reactive" as well.

*mDNSResponder may have some responsibility in the sense that it could have decided "this is silly, stop allowing this", but you can't really know if that's realistic until the underlying cause is identified.

Related to that point:

We are experiencing abnormal battery drain during sleep on several machines that installed our product.

What does your product actually "do", both in terms of how it runs (app/agent/daemon) and what it actually "does", particularly in terms of power management, networking, and Bonjour activity? In terms of your own products role here, one thing I would look closely at is any place where you "react" to system activity/events. The basic flow problems like this often have looks something like this:

  1. Your process reacts to some event (for example, sleep start) by doing "something" that triggers the first wake.

  2. The wake assertion prevents sleep.

  3. Your process reacts to that by resetting the conditions that created one.

  4. The system tries to sleep again and we loop back to #1.

Note that this is the VERY simplified, high-level description of the logic flow. Real-world examples tend to be far more complicated, often crossing multiple processes/components/subsystems. It's also why the term "regression" can be misleading, as it implies that there was a specific mistake which can be "undone". It's more often the case that there isn't really any direct connection between the changes and the final result. More importantly, those changes are often bug fixes which can't/shouldn't be reversed, so any fix will need to occur somewhere else.

Whether there are unified log predicates or private logging options to further trace the root cause (e.g., process holding IO or waking CPU without explicit assertion).

Yes, there are a few options here:

  • A standard Sysdiagnose can often be quite helpful. Assuming those log messages came from the system log, they establish a fairly clear "cycle" (note that the log messages are spaced at very precise intervals) and whatever is actually going on is very likely happening inside that "loop". I generally use those log messages to set up a time boundary (so the log is easier to work with), then focus on exactly what happened just before and just after each message to figure out "why" each event happened.
2025-06-28 21:57:29 Sleep Entering Sleep state due to 'Maintenance Sleep':TCPKeepAlive=active Using Batt (Charge:76%) 3 secs    
2025-06-28 21:57:31 Wake Requests [process=mDNSResponder request=Maintenance deltaSecs=7198 wakeAt=2025-06-28 23:57:29 ...]
2025-06-28 21:57:38 Sleep Entering Sleep state due to 'Maintenance Sleep':TCPKeepAlive=active Using Batt (Charge:76%) 3 secs    
  • mDNSResponder has its own debug profile which will remove most of its redactions. This is particularly helpful if/when Bonjour activity is involved.

  • If you're working with a dedicated test device or your own machine, the "Sysdiagnose (Unredacted)" profile will greatly increase the detail of the entire log. However, be aware that using this profile has significant privacy implications so it's not something I would ask normal users/customers to use. Indeed, it's included on a site primarily as a tool for developers, NOT because we ask for that particular log type.

On that last point, if you capture this issue on a test machine using the unredacted profile and decide to file a bug on this, please note in the bug that the log came from a dedicated test device that you intentionally set up to not include any privacy-sensitive information.

We can provide access to full logs, configuration profiles, and system diagnostics if needed.

If you file a bug and post the bug number back here, I can try and take a look. In that bug, please include what your components actually "are" as well as the background of what your product actually "does", as well as the sysdiagnose data itself.

Having said that, I'm on vacation next week, so if you haven't heard back in a week or two, post back on this thread again just in case it slipped off my radar.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Reordering questions for clarity:

How can we trace what exactly is triggering the repeated wake (e.g., a subsystem, implicit assertion, etc.)?

mDNSResponder, which is the daemon which handles DNS resolution and, more importantly, manages Bonjour:

Wake Requests [process=mDNSResponder request=Maintenance...

Whether this behavior is expected under certain conditions or indicates a regression or misbehavior in power management.

The power management system itself isn't really at fault, as its job is to "do what it's told" and it's waking the system exactly as it was "told" to. Similarly, I don't think mDNSResponder itself is directly responsible*, as its role is large "reactive" as well.

*mDNSResponder may have some responsibility in the sense that it could have decided "this is silly, stop allowing this", but you can't really know if that's realistic until the underlying cause is identified.

Related to that point:

We are experiencing abnormal battery drain during sleep on several machines that installed our product.

What does your product actually "do", both in terms of how it runs (app/agent/daemon) and what it actually "does", particularly in terms of power management, networking, and Bonjour activity? In terms of your own products role here, one thing I would look closely at is any place where you "react" to system activity/events. The basic flow problems like this often have looks something like this:

  1. Your process reacts to some event (for example, sleep start) by doing "something" that triggers the first wake.

  2. The wake assertion prevents sleep.

  3. Your process reacts to that by resetting the conditions that created one.

  4. The system tries to sleep again and we loop back to #1.

Note that this is the VERY simplified, high-level description of the logic flow. Real-world examples tend to be far more complicated, often crossing multiple processes/components/subsystems. It's also why the term "regression" can be misleading, as it implies that there was a specific mistake which can be "undone". It's more often the case that there isn't really any direct connection between the changes and the final result. More importantly, those changes are often bug fixes which can't/shouldn't be reversed, so any fix will need to occur somewhere else.

Whether there are unified log predicates or private logging options to further trace the root cause (e.g., process holding IO or waking CPU without explicit assertion).

Yes, there are a few options here:

  • A standard Sysdiagnose can often be quite helpful. Assuming those log messages came from the system log, they establish a fairly clear "cycle" (note that the log messages are spaced at very precise intervals) and whatever is actually going on is very likely happening inside that "loop". I generally use those log messages to set up a time boundary (so the log is easier to work with), then focus on exactly what happened just before and just after each message to figure out "why" each event happened.
2025-06-28 21:57:29 Sleep Entering Sleep state due to 'Maintenance Sleep':TCPKeepAlive=active Using Batt (Charge:76%) 3 secs    
2025-06-28 21:57:31 Wake Requests [process=mDNSResponder request=Maintenance deltaSecs=7198 wakeAt=2025-06-28 23:57:29 ...]
2025-06-28 21:57:38 Sleep Entering Sleep state due to 'Maintenance Sleep':TCPKeepAlive=active Using Batt (Charge:76%) 3 secs    
  • mDNSResponder has its own debug profile which will remove most of its redactions. This is particularly helpful if/when Bonjour activity is involved.

  • If you're working with a dedicated test device or your own machine, the "Sysdiagnose (Unredacted)" profile will greatly increase the detail of the entire log. However, be aware that using this profile has significant privacy implications so it's not something I would ask normal users/customers to use. Indeed, it's included on a site primarily as a tool for developers, NOT because we ask for that particular log type.

On that last point, if you capture this issue on a test machine using the unredacted profile and decide to file a bug on this, please note in the bug that the log came from a dedicated test device that you intentionally set up to not include any privacy-sensitive information.

We can provide access to full logs, configuration profiles, and system diagnostics if needed.

If you file a bug and post the bug number back here, I can try and take a look. In that bug, please include what your components actually "are" as well as the background of what your product actually "does", as well as the sysdiagnose data itself.

Having said that, I'm on vacation next week, so if you haven't heard back in a week or two, post back on this thread again just in case it slipped off my radar.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Hi Kevin ( @DTS Engineer) and thanks for your thorough reply. Per your query so our service (from type launchDaemon) do listen for system sleep events using the NSWorkspaceWillSleepNotification and NSWorkspaceDidWakeNotification via NSWorkspace.sharedWorkspace.notificationCenter.

When getting the sleep event, we close all unnecessary components and only use minimal keepalive communication via websocket to a remote server.

When getting the wake event, we reactivate the extra components implement the logic of our network product.

In addition, we are using network extension that runs on a separated process, and runs several providers that intercept tcp/udp connections, filter packets, data and more. this extension isn't informed of the sleep wake events and continue as usual assuming that when the computer move to deep sleep, the process will be halted.

Another point worth mentioning, our service was once running as a launchAgent, and now converted to run as launchDaemon, can it have an effect of the power consumption ?

Perhaps with this information you'd be able to provide more insights ?

Thanks !

So, first off:

Another point worth mentioning, our service was once running as a launchAgent, and now converted to run as launchDaemon.

NSWorkspace is an AppKit API, which means Daemon's are NOT allowed to use it. Your daemon should not even be LINKING against AppKit. See TN2083.

Can it have an effect on the power consumption ?

Not directly being the consequences of entangling a daemon with the login session (through AppKit) are difficult to predict.

Referencing the pattern from my previous message:

(1) Your process reacts to some event (for example, sleep start) by doing "something" that triggers the first wake.

When getting the sleep event, we close all unnecessary components and only use minimal keepalive communication via WebSocket to a remote server.

You should be shutting down "everything". Leaving anything open creates unnecessary risk and complication. Also, what network API are you using here?

(3) Your process reacts to that by resetting the conditions that created one.

When getting the wake event, we reactivate the extra components and implement the logic of our network product.

I'm not sure why you're getting these notifications, but one thing to try would be throttling your "wake" logic above to see if that will allow normal sleep.

In addition, we are using a network extension that runs on a separate process, and runs several providers that intercept TCP/UDP connections, filter packets, data, and more. This extension isn't informed of the sleep wake events and continues as usual assuming that when the computer moves to deep sleep, the process will be halted.

Keep in mind that the "sleep" process (like most power transitions) is a multilayered sequence where lower-level systems don't "find out" about the event until the higher-level system has completed its own sequence. As a more straightforward example, take this sequence:

  1. You select "Shutdown" from the Apple menu.

  2. Apps start quitting.

  3. One app blocks the quit (for example, unsaved work).

  4. The dialog is presented, and you cancel Shutdown.

From the kernel/lower-level systems perspective, "nothing" actually happened, and the system was just continuing to run normally. They were never told about #1, so #4 is irrelevant. From the kernel side, it doesn't start "shutdown" until the process is far enough along that it cannot be canceled and will always proceed to completion. A similar situation applies here, where the lower-level components (like the network layer) don't start sleep until higher-level activity has already stopped.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Excessive batter drain in macOS during sleep mode.
 
 
Q