javaspringmqttmosquittohivemq

HiveMQ Java library fails to automatically reconnect to broker


I'm using the HiveMQ library in my Java Spring application to connect to a Mosquitto instance as I find it more user-friendly compared to the Paho client. But something is going wrong with the automatic reconnection. From time to time the connection is lost and the application doesn't succeed in reconnecting (see logs 1). This can also be triggered by restarting the Mosquitto broker itself (see logs 2).

This is my client builder code with additional logging in the disconnect to check if the credentials are still correct:

        client = MqttClient.builder()
                .useMqttVersion5()
                .identifier(identifier)
                .serverHost(host)
                .serverPort(port)
                .sslWithDefaultConfig()
                // https://www.hivemq.com/blog/hivemq-mqtt-client-features/reconnect-handling/
                .automaticReconnectWithDefaultConfig()
                .addDisconnectedListener(context -> logger.error("MQTT user {} with identifier {} on {}:{} has disconnected reason: {}",
                        username, identifier, host, port, context.getCause().getMessage()))
                .buildAsync();


        client.connectWith()
                .simpleAuth()
                .username(username)
                .password(password.getBytes())
                .applySimpleAuth()
                .cleanStart(false)
                .keepAlive(60)
                .send();

1/ This is shown in my logs after the connection has been lost by the application itself:

2022-03-16 02:10:33.502 ERROR 1 --- [client.mqtt-1-2] MqttConfig : MQTT user *** with identifier SERVICE on ***:8883 has disconnected reason: Timeout while waiting for PINGRESP
2022-03-16 02:11:25.090 ERROR 1 --- [client.mqtt-1-2] MqttConfig : MQTT user *** with identifier SERVICE on ***:8883 has disconnected reason: CONNECT failed as CONNACK contained an Error Code: NOT_AUTHORIZED.
2022-03-16 02:12:27.200 ERROR 1 --- [client.mqtt-1-2] MqttConfig : MQTT user *** with identifier SERVICE on ***:8883 has disconnected reason: Timeout while waiting for CONNACK

2/ This is the logs after the broker has been restarted, some expected time-outs, but also in the end "not authorized":

2022-03-16 10:17:37.178 ERROR 1 --- [client.mqtt-1-2] MqttConfig     : MQTT user *** with identifier SERVICE on ***:8883 has disconnected reason: Server closed connection without DISCONNECT.
2022-03-16 10:17:48.441 ERROR 1 --- [client.mqtt-1-2] MqttConfig     : MQTT user *** with identifier SERVICE on ***:8883 has disconnected reason: io.netty.channel.ConnectTimeoutException: connection timed out: ***/***:8883
2022-03-16 10:18:00.747 ERROR 1 --- [client.mqtt-1-2] MqttConfig     : MQTT user *** with identifier SERVICE on ***:8883 has disconnected reason: io.netty.channel.ConnectTimeoutException: connection timed out: ***/***:8883
2022-03-16 10:18:10.625 ERROR 1 --- [client.mqtt-1-2] MqttConfig     : MQTT user *** with identifier SERVICE on ***:8883 has disconnected reason: io.netty.channel.AbstractChannel$AnnotatedConnectException: finishConnect(..) failed: No route to host: ***/***:8883
2022-03-16 10:18:26.845 ERROR 1 --- [client.mqtt-1-2] MqttConfig     : MQTT user *** with identifier SERVICE on ***:8883 has disconnected reason: io.netty.channel.ConnectTimeoutException: connection timed out: ***/***:8883
2022-03-16 10:18:42.584 ERROR 1 --- [client.mqtt-1-2] MqttConfig     : MQTT user *** with identifier SERVICE on ***:8883 has disconnected reason: CONNECT failed as CONNACK contained an Error Code: NOT_AUTHORIZED.

In both cases, the connection is back to normal with an application restart.

any ideas?


Solution

  • It appears that your question is answered in this issue:

    If you set the username and password on the connect call, they will not be stored and reused when the client reconnects (for security reasons).

    The following code (from the issue linked above) demonstrates the approach:

    Mqtt3Client.builder()
       .identifier("ePCR mobile-" + currentTimeMillis())
       .serverHost(config.getHost())
       .serverPort(config.getPort())
       .automaticReconnectWithDefaultConfig()
       .simpleAuth()
           .username(config.getUsername())
           .password(config.getPassword())
           .applySimpleAuth()
       .buildRx();