I have a small amount of Things that have been created after MQTT Home Assistant discovery. These work quite well in general, but I’ve noticed they can easily be knocked offline by a change in connection status to the broker.
I run a mosquitto instance in docker which I access via a Traefik proxy. If any of the following occur:
Traefik is restarted
Mosquitto is restarted
The broker Thing in OpenHAB is updated (eg. change the reconnect value, but maybe others)
In a short period, the MQTT.homeassistant Things change to the Unknown status.
During this time, the OpenHAB log reports the MQTT broker was disconnected but then reconnected. eg.
2025-07-14 04:02:34.966 [INFO ] [.reconnect.PeriodicReconnectStrategy] - Try to restore connection to 'mqtt.myhostname'. Next attempt in 60000ms
2025-07-14 04:02:34.967 [INFO ] [.transport.mqtt.MqttBrokerConnection] - Starting MQTT broker connection to 'mqtt.myhostname' with clientid 17fa1aa6-9db5-4d69-a3e4-610d3bd47094
To fix, I usually open each Thing and resave it. It then becomes ONLINE again. There is nothing in the logs about the Things themselves changing status.
Any other MQTT Things I have (Generic MQTT), recover without issue.
This bug or incompatibility means any upgrade to mosquitto or traefik is coupled to OpenHAB in a way that isn’t necessary. Is anyone else seeing similar?
This problem exists way back even before OH4 and has not been resolved since.
Why should it be fixed now with 5.0? What if I would like to stay with OH4 and keep my system in 32bit and avoid all the hassle of replacing my working system OS.
Personally I am considering abandoning OH all together due to a lot of issues, complexities and incompatibility of many add-ons. I have been using it since OH2 but in the last couple of years it has been breaking repeatedly in almost every update.
I can confirm that the problem still exists in openhab 5.0.1
Running;
Openhab 5.0.1, installed with openHabian v1.10.5
Raspberry PI 5, Model B, Rev 1.0
Today all of my MQTT Home Assistant discovery Things changed to Unknown. All these Things/Items have been working for many days (more than a month) and then without any obvious reason they all were no longer controllable through the openhab sitemap. When I logged into openhab via it’s IP address all MQTT Home Assistant discovery Things were in Unknown state.
@andre solution of opening each Thing and saving it works. The Thing changes to Online. Although it will be annoying as a long-term solution.
The UI Log Viewer reports the following when I try to turn an Item ON / OFF (both are dimmers).
For an unknown Thing:
WARN
org.openhab.binding.mqtt.generic.AbstractMQTTThingHandler
Channel mqtt:homeassistant:Mosquitto:feit_dimsmart_04:dimmer_switch not supported!
For a Thing that has been opened and saved:
info_circle 20:57:04.743 INFO
openhab.event.ItemCommandEvent
Item 'feit_dimsmart_01_Dimmer_Switch' received command ON
info_circle 20:57:04.744 INFO
openhab.event.ItemStatePredictedEvent
Item 'feit_dimsmart_01_Dimmer_Switch' predicted to become ON
info_circle 20:57:04.744 INFO
openhab.event.ItemStateUpdatedEvent
Item 'feit_dimsmart_01_Dimmer_Switch' updated to 100
info_circle 20:57:04.744 INFO
openhab.event.ItemStateChangedEvent
Item 'feit_dimsmart_01_Dimmer_Switch' changed from 0 to 100
info_circle 20:57:04.763 INFO
openhab.event.ItemStateUpdatedEvent
Item 'feit_dimsmart_01_Dimmer_Switch' updated to 100
info_circle 20:57:04.817 INFO
openhab.event.ItemStateUpdatedEvent
Item 'feit_dimsmart_01_Dimmer_Switch' updated to 100
info_circle 20:57:05.460 INFO
openhab.event.ItemCommandEvent
Item 'feit_dimsmart_01_Dimmer_Switch' received command OFF
info_circle 20:57:05.461 INFO
openhab.event.ItemStatePredictedEvent
Item 'feit_dimsmart_01_Dimmer_Switch' predicted to become OFF
info_circle 20:57:05.463 INFO
openhab.event.ItemStateUpdatedEvent
Item 'feit_dimsmart_01_Dimmer_Switch' updated to 0
info_circle 20:57:05.463 INFO
openhab.event.ItemStateChangedEvent
Item 'feit_dimsmart_01_Dimmer_Switch' changed from 100 to 0
info_circle 20:57:05.484 INFO
openhab.event.ItemStateUpdatedEvent
Item 'feit_dimsmart_01_Dimmer_Switch' updated to 0
info_circle 20:57:05.525 INFO
openhab.event.ItemStateUpdatedEvent
Item 'feit_dimsmart_01_Dimmer_Switch' updated to 0
Edit 1: Opening and saving a Thing reports the following in the log viewer:
INFO
openhab.event.ThingStatusInfoChangedEvent
Thing 'mqtt:homeassistant:Mosquitto:feit_dimsmart_05' changed from UNKNOWN to ONLINE
info_circle 21:19:53.216 INFO
openhab.event.ItemStateUpdatedEvent
Item 'feit_dimsmart_05_Dimmer_Switch' updated to 34.90196078431372549019607843137255
info_circle 21:19:53.217 INFO
openhab.event.ItemStateChangedEvent
Item 'feit_dimsmart_05_Dimmer_Switch' changed from 0 to 34.90196078431372549019607843137255
Edit 2: FYI, Rebooting the dimmer switches did not change anything, openhab continued to report the Unknown state.
Any help appreciated.
Let me know how I can assist with troubleshooting this issue.
Not an expert, but is the app sending to MQTT configured to “retain” the HA configs? Could use MQTT explorer to check while purposefully causing it to happen.
EDIT: Another idea that I think worked when I was playing with the HA Configs; After the configs are found and retained deactivate them in the app sending them. The configs themselves are not dynamic, just the inputs.
I could check that.. tho it would only show a bug imo. The config topics should be only used for discovery. Once things and items are setup, i’d expect them to be less relevant if at all.
Agree, hence my other thought to deactive after discovery to see if that helps. If they are persisted, then it is probably the availability topic in the HA config that is causing the problem. That wouldn’t affect the persisted topic in the generic MQTT but cause the HA topic to show offline. The mystery would be why it doesn’t recover gracefully after the device restarts.
In my case for all devices the only message that is set to retain is the birth and will messages (LWT message). All other values sent via MQTT are not retained. This is the case for all MQTT devices. Things may either be manual created and configured or created through the MQTT Home assistant discovery process.
Interesting side note: While opening and saving the Unknown Things yesterday I discovered that I had two Things configured for the same device.
One manually, i.e. all the channels and items were created by me one by one: mqtt:topic:Mosquitto:LivingroomHP
The other using the MQTT Home assistant discovery and automatic creation method. mqtt:homeassistant_382ce5640edd:Mosquitto:LivingroomHP
The manually created one was Online whereas the Home assistant one was unknown.
It is not my binding, but what I think would be helpful is a Debug log on MQTT Home-assistant via the UI-Settings-Addon-Settings-MQTT and drill down to MQTT-HA. Then execute one of the actions that leads to the problem. No need for anything on the event log. Also, it might be helpful to post the HA configuration JSON that applies to the Item.
The thought in my other suggestion to look at MQTT Explorer during the problem is to eliminate the third-party app (traefik, feit, etc.) as the cause. HA is actually moving away from the HA configs. There could be variability in how HA configs are implemented by different apps that may cause an issue in OH. I had no problem (like reported above) when I briefly used HA configs with ZWave-JS-UI a few months ago. For other reasons I just use generic MQTT things now.
Finally, as noted above, the HA configs include an availability topic whereas generic MQTT channels do not. Therefore, channels from generic things would not be affected (if they are retained and included in your persistance). “Retained” in this context applies to third party app settings, not the settings of the MQTT in OH.
I have been using MQTT explorer, the switch and MQTT messages are all working. I can send commands via MQTT Explorer and change the state of the switch. I don’t think it’s related to the switch.
The MQTT Things that I manually create do contain availability topics. Selecting “show advanced” allows you to specify the availability topic for the device, the LWT (last will and testament messages), by specifying the available and unavailable payloads. The MQTT Home Assistant process appears to be doing the same.
FYI, from MQTT explorer, the switch that is still “unknown” in Openhab”. Sending a command via MQTT Explorer works, even though it’s Unknow in Openhab.
I guess I could just switch to creating MQTT Things manually, but it would be helpful to determine why the MQTT Home Assistant binding has these issues.
The simplest way to cause the Things to become “Unknown” is to simply stop the MQTT broker server and restart it. It immediately sends all discovered Things into the “Unknown”.
This happens, for example, if a Mosquito docker container is being updated (stop and re-start). Also when Z2M or Zwave2JS updates, all their nodes become “Unknown”. When this happens I need to go to all my “Things” and do a sequence of Disable/Enable to get them to update to Online.
Definitely open an issue and reference this forum post.
From your data I still wonder why the HA configs do not go back online when the connection is restored. The WARN seems to indicate that the Channel UID is missing after the connection is restored and needs to be rediscovered. However, it needs to be looked at by the developer
This is a good approach. I’ve tried to elevate my debug level for mqtt.homeassistant in the UI and get an error:
2025-10-07 10:58:21.685 [ERROR] [internal.JSONResponseExceptionMapper] - Unexpected exception occurred while processing REST request.
java.lang.RuntimeException: Unable to set level for logger
at org.apache.karaf.log.core.internal.LogServiceLog4j2XmlImpl.setLevel(LogServiceLog4j2XmlImpl.java:139) ~[?:?]
at org.apache.karaf.log.core.internal.LogServiceImpl.setLevel(LogServiceImpl.java:114) ~[?:?]
at org.openhab.core.karaf.internal.LoggerResource.putLoggers(LoggerResource.java:106) ~[?:?]
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[?:?]
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
at java.lang.reflect.Method.invoke(Method.java:569) ~[?:?]
at org.apache.cxf.service.invoker.AbstractInvoker.performInvocation(AbstractInvoker.java:179) ~[bundleFile:3.6.2]
at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:96) ~[bundleFile:3.6.2]
at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:201) ~[bundleFile:3.6.2]
at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:104) ~[bundleFile:3.6.2]
at org.apache.cxf.interceptor.ServiceInvokerInterceptor$1.run(ServiceInvokerInterceptor.java:59) ~[bundleFile:3.6.2]
at org.apache.cxf.interceptor.ServiceInvokerInterceptor.handleMessage(ServiceInvokerInterceptor.java:96) ~[bundleFile:3.6.2]
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:307) ~[bundleFile:3.6.2]
at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121) ~[bundleFile:3.6.2]
at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:265) ~[bundleFile:3.6.2]
at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:234) ~[bundleFile:3.6.2]
at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:208) ~[bundleFile:3.6.2]
at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:160) ~[bundleFile:3.6.2]
at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:225) ~[bundleFile:3.6.2]
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:304) ~[bundleFile:3.6.2]
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPut(AbstractHTTPServlet.java:234) ~[bundleFile:3.6.2]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:520) ~[bundleFile:4.0.4]
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:279) ~[bundleFile:3.6.2]
at org.ops4j.pax.web.service.spi.servlet.OsgiInitializedServlet.service(OsgiInitializedServlet.java:102) ~[bundleFile:?]
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:799) ~[bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1656) ~[bundleFile:9.4.54.v20240208]
at org.ops4j.pax.web.service.spi.servlet.OsgiFilterChain.doFilter(OsgiFilterChain.java:113) ~[bundleFile:?]
at org.ops4j.pax.web.service.jetty.internal.PaxWebServletHandler.doHandle(PaxWebServletHandler.java:334) ~[bundleFile:?]
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143) ~[bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:600) ~[bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) ~[bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235) ~[bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1624) ~[bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233) ~[bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1440) ~[bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188) ~[bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:505) ~[bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1594) ~[bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186) ~[bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1355) ~[bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) ~[bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:234) ~[bundleFile:9.4.54.v20240208]
at org.ops4j.pax.web.service.jetty.internal.PrioritizedHandlerCollection.handle(PrioritizedHandlerCollection.java:96) ~[bundleFile:?]
at org.eclipse.jetty.server.handler.gzip.GzipHandler.handle(GzipHandler.java:722) ~[bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) ~[bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.server.Server.handle(Server.java:516) ~[bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:487) ~[bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:732) [bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:479) [bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:277) [bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311) [bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105) [bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104) [bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:338) [bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:315) [bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:173) [bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131) [bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:409) [bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883) [bundleFile:9.4.54.v20240208]
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034) [bundleFile:9.4.54.v20240208]
at java.lang.Thread.run(Thread.java:840) [?:?]
Caused by: org.w3c.dom.DOMException: NOT_FOUND_ERR: An attempt is made to reference a node in a context where it does not exist.
at com.sun.org.apache.xerces.internal.dom.ParentNode.internalInsertBefore(ParentNode.java:364) ~[?:?]
at com.sun.org.apache.xerces.internal.dom.ParentNode.insertBefore(ParentNode.java:286) ~[?:?]
at org.apache.karaf.log.core.internal.LogServiceLog4j2XmlImpl.insertIndented(LogServiceLog4j2XmlImpl.java:168) ~[?:?]
at org.apache.karaf.log.core.internal.LogServiceLog4j2XmlImpl.setLevel(LogServiceLog4j2XmlImpl.java:121) ~[?:?]
... 61 more
So I tried the same in console. Also failed.
openhab> log:set debug org.openhab.binding.mqtt.homeassistant
Error executing command: Unable to set level for logger
Am I doing something wrong? Is my install in an odd state? I’m running v4.3.7 (after having the issue on 4.3.5 and upgrading).
EDIT: I have a custom appender for zwave and it’s probably something to do with that. I put the mqtt.homeassistant binding into DEBUG using the same method.
Ok, I was able to put both the mqtt binding and mqtt.homeassistant into DEBUG. I then restarted my traefik instance that acts as a gateway between openhab and mosquitto.
My Home Assistant MQTT things almost instantly change to NOT CONNECTED (RED)
After a few seconds, they change again to UNKNOWN (YELLOW)
The mqtt.homeassistantlog in DEBUG has no lines during this
the mqtt DEBUG log shows the channels being UNSUBSCRIBED (see below)
If you restart OpenHAB altogether, these Things work just fine
My other Generic MQTT Things, using the same MQTT broker and traefik proxy don’t have this issue being interrupted when there is a network issue or restart
Seems to me there is a retry mechanism/trigger missing in the Home Assistant variant of the Binding. I’ll add this all to the GitHub issue.
You should be able to do it via the UI. In the Admin Console, go to Add Ons / MQTT Binding / Settings (the little gear icon) and then there are drop downs for each component.
I’ve previously use the log4j.xml config file on disk to create seperate files for zwave and I think this interferes with this simpler method - so I had to do more.
Also - looking at the Binding’s code, it seems to look for a post in the availability topic before it will become alive again. This appears to be “newish” because I’m sure this issue is fairly recent. None of my HA devices do this and so if I make them do so, it’d probably fix the problem. But it’d be nice to not have to.
These are mentioned in the documentation here and here.