diff --git a/src/async_client.cpp b/src/async_client.cpp
index c536b77..1a89662 100644
--- a/src/async_client.cpp
+++ b/src/async_client.cpp
@@ -34,27 +34,6 @@
 	#define MQTTAsync_createOptions_initializer5 { {'M', 'Q', 'C', 'O'}, 0, 0, 100, MQTTVERSION_5 }
 #endif
 
-/////////////////////////////////////////////////////////////////////////////
-// Paho C logger
-
-enum LOG_LEVELS {
-	INVALID_LEVEL = -1,
-	TRACE_MAX = 1,
-	TRACE_MED,
-	TRACE_MIN,
-	TRACE_PROTOCOL,
-	LOG_PROTOCOL = TRACE_PROTOCOL,
-	LOG_ERROR,
-	LOG_SEVERE,
-	LOG_FATAL,
-};
-
-extern "C" {
-	void Log(enum LOG_LEVELS, int, const char *, ...);
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
 namespace mqtt {
 
 /////////////////////////////////////////////////////////////////////////////
@@ -150,8 +129,6 @@ async_client::~async_client()
 // is notified of success on a normal connect with callbacks. 
 void async_client::on_connected(void* context, char* cause)
 {
-	::Log(TRACE_MIN, -1, "[cpp] on_connected");
-
 	if (context) {
 		async_client* cli = static_cast<async_client*>(context);
 		callback* cb = cli->userCallback_;
@@ -172,8 +149,6 @@ void async_client::on_connected(void* context, char* cause)
 // MQTTAsync_setCallbacks(). 
 void async_client::on_connection_lost(void *context, char *cause)
 {
-	::Log(TRACE_MIN, -1, "[cpp] on_connection lost");
-
 	if (context) {
 		async_client* cli = static_cast<async_client*>(context);
 		callback* cb = cli->userCallback_;
@@ -193,6 +168,22 @@ void async_client::on_connection_lost(void *context, char *cause)
 	}
 }
 
+// Callback from the C lib for when a disconnect packet is received from
+// the server.
+void async_client::on_disconnected(void* context, MQTTProperties* cprops,
+								   MQTTReasonCodes reasonCode)
+{
+	if (context) {
+		async_client* cli = static_cast<async_client*>(context);
+		auto& disconnectedHandler = cli->disconnectedHandler_;
+
+		if (disconnectedHandler) {
+			properties props(*cprops);
+			disconnectedHandler(props, ReasonCode(reasonCode));
+		}
+	}
+}
+
 // Callback for when a subscribed message arrives.
 // This is called from the MQTTAsync_messageArrived registered via 
 // MQTTAsync_setCallbacks(). 
@@ -365,6 +356,13 @@ void async_client::set_connection_lost_handler(connection_handler cb)
 						&async_client::on_connection_lost));
 }
 
+void async_client::set_disconnected_handler(disconnected_handler cb)
+{
+	disconnectedHandler_ = cb;
+	check_ret(::MQTTAsync_setDisconnected(cli_, this,
+						&async_client::on_disconnected));
+}
+
 void async_client::set_message_callback(message_handler cb)
 {
 	msgHandler_ = cb;
diff --git a/src/mqtt/async_client.h b/src/mqtt/async_client.h
index 4323071..4bbd95c 100644
--- a/src/mqtt/async_client.h
+++ b/src/mqtt/async_client.h
@@ -32,6 +32,7 @@
 #include "mqtt/delivery_token.h"
 #include "mqtt/iclient_persistence.h"
 #include "mqtt/iaction_listener.h"
+#include "mqtt/properties.h"
 #include "mqtt/exception.h"
 #include "mqtt/message.h"
 #include "mqtt/callback.h"
@@ -84,6 +85,8 @@ public:
 	using message_handler = std::function<void(const_message_ptr)>;
 	/** Handler type for when a connecion is made or lost */
 	using connection_handler = std::function<void(const string& cause)>;
+	/** Handler type for when a disconnect packet is received */
+	using disconnected_handler = std::function<void(const properties&, ReasonCode)>;
 
 private:
 	/** Lock guard type for this class */
@@ -105,10 +108,12 @@ private:
 	std::unique_ptr<MQTTClient_persistence> persist_;
 	/** Callback supplied by the user (if any) */
 	callback* userCallback_;
-	/** Connection handler  */
+	/** Connection handler */
 	connection_handler connHandler_;
-	/** Connection lost handler  */
+	/** Connection lost handler */
 	connection_handler connLostHandler_;
+	/** Disconnected handler */
+	disconnected_handler disconnectedHandler_;
 	/** Message handler (if any) */
 	message_handler msgHandler_;
 	/** Copy of connect token (for re-connects) */
@@ -120,9 +125,11 @@ private:
 	/** A queue of messages for consumer API */
 	consumer_queue_type que_;
 
-	/** Callbacks from the C library  */
+	/** Callbacks from the C library */
 	static void on_connected(void* context, char* cause);
 	static void on_connection_lost(void *context, char *cause);
+	static void on_disconnected(void* context, MQTTProperties* cprops,
+								MQTTReasonCodes reasonCode);
 	static int  on_message_arrived(void* context, char* topicName, int topicLen,
 								   MQTTAsync_message* msg);
 	static void on_delivery_complete(void* context, MQTTAsync_token tok);
@@ -234,6 +241,11 @@ public:
 	 * @param cb Callback functor for when the connection is lost.
 	 */
 	void set_connection_lost_handler(connection_handler cb) /*override*/;
+	/**
+	 * Callback for when a disconnect packet is received from the server.
+	 * @param cb Callback for when the disconnect packet is received.
+	 */
+	void set_disconnected_handler(disconnected_handler cb) /*override*/;
 	/**
 	 * Sets the callback for when a message arrives from the broker.
 	 * Note that the application can only have one message handler which can
diff --git a/src/mqtt/thread_queue.h b/src/mqtt/thread_queue.h
index 94c3fea..5dafe6e 100644
--- a/src/mqtt/thread_queue.h
+++ b/src/mqtt/thread_queue.h
@@ -31,6 +31,7 @@
 #include <limits>
 #include <deque>
 #include <queue>
+#include <algorithm>
 
 namespace mqtt {
 
@@ -102,9 +103,9 @@ public:
 	/**
 	 * Constructs a queue with the specified capacity.
 	 * @param cap The maximum number of items that can be placed in the
-	 *  		  queue.
+	 *  		  queue. The minimum capacity is 1.
 	 */
-	explicit thread_queue(size_t cap) : cap_(cap) {}
+	explicit thread_queue(size_t cap) : cap_(std::max<size_type>(cap, 1)) {}
 	/**
 	 * Determine if the queue is empty.
 	 * @return @em true if there are no elements in the queue, @em false if
@@ -148,11 +149,11 @@ public:
 	 */
 	void put(value_type val) {
 		unique_guard g(lock_);
-		size_type n = que_.size();
-		if (n >= cap_)
+		if (que_.size() >= cap_)
 			notFullCond_.wait(g, [=]{return que_.size() < cap_;});
+        bool wasEmpty = que_.empty();
 		que_.emplace(std::move(val));
-		if (n == 0) {
+		if (wasEmpty) {
 			g.unlock();
 			notEmptyCond_.notify_one();
 		}
@@ -187,11 +188,11 @@ public:
 	template <typename Rep, class Period>
 	bool try_put_for(value_type* val, const std::chrono::duration<Rep, Period>& relTime) {
 		unique_guard g(lock_);
-		size_type n = que_.size();
-		if (n >= cap_ && !notFullCond_.wait_for(g, relTime, [=]{return que_.size() < cap_;}))
+		if (que_.size() >= cap_ && !notFullCond_.wait_for(g, relTime, [=]{return que_.size() < cap_;}))
 			return false;
+        bool wasEmpty = que_.empty();
 		que_.emplace(std::move(val));
-		if (n == 0) {
+		if (wasEmpty) {
 			g.unlock();
 			notEmptyCond_.notify_one();
 		}
@@ -210,11 +211,11 @@ public:
 	template <class Clock, class Duration>
 	bool try_put_until(value_type* val, const std::chrono::time_point<Clock,Duration>& absTime) {
 		unique_guard g(lock_);
-		size_type n = que_.size();
-		if (n >= cap_ && !notFullCond_.wait_until(g, absTime, [=]{return que_.size() < cap_;}))
+		if (que_.size() >= cap_ && !notFullCond_.wait_until(g, absTime, [=]{return que_.size() < cap_;}))
 			return false;
+        bool wasEmpty = que_.empty();
 		que_.emplace(std::move(val));
-		if (n == 0) {
+		if (wasEmpty) {
 			g.unlock();
 			notEmptyCond_.notify_one();
 		}
@@ -228,12 +229,11 @@ public:
 	 */
 	void get(value_type* val) {
 		unique_guard g(lock_);
-		auto n = que_.size();
-		if (n == 0)
+		if (que_.empty())
 			notEmptyCond_.wait(g, [=]{return !que_.empty();});
 		*val = std::move(que_.front());
 		que_.pop();
-		if (n == cap_) {
+		if (que_.size() == cap_-1) {
 			g.unlock();
 			notFullCond_.notify_one();
 		}
@@ -246,12 +246,11 @@ public:
 	 */
 	value_type get() {
 		unique_guard g(lock_);
-		auto n = que_.size();
-		if (n == 0)
+		if (que_.empty())
 			notEmptyCond_.wait(g, [=]{return !que_.empty();});
 		value_type val = std::move(que_.front());
 		que_.pop();
-		if (n == cap_) {
+		if (que_.size() == cap_-1) {
 			g.unlock();
 			notFullCond_.notify_one();
 		}
@@ -267,12 +266,11 @@ public:
 	 */
 	bool try_get(value_type* val) {
 		unique_guard g(lock_);
-		auto n = que_.size();
-		if (n == 0)
+		if (que_.empty())
 			return false;
 		*val = std::move(que_.front());
 		que_.pop();
-		if (n == cap_) {
+		if (que_.size() == cap_-1) {
 			g.unlock();
 			notFullCond_.notify_one();
 		}
@@ -291,12 +289,11 @@ public:
 	template <typename Rep, class Period>
 	bool try_get_for(value_type* val, const std::chrono::duration<Rep, Period>& relTime) {
 		unique_guard g(lock_);
-		auto n = que_.size();
-		if (n == 0 && !notEmptyCond_.wait_for(g, relTime, [=]{return !que_.empty();}))
+		if (que_.empty() && !notEmptyCond_.wait_for(g, relTime, [=]{return !que_.empty();}))
 			return false;
 		*val = std::move(que_.front());
 		que_.pop();
-		if (n == cap_) {
+		if (que_.size() == cap_-1) {
 			g.unlock();
 			notFullCond_.notify_one();
 		}
@@ -315,12 +312,11 @@ public:
 	template <class Clock, class Duration>
 	bool try_get_until(value_type* val, const std::chrono::time_point<Clock,Duration>& absTime) {
 		unique_guard g(lock_);
-		auto n = que_.size();
-		if (n == 0 && !notEmptyCond_.wait_until(g, absTime, [=]{return !que_.empty();}))
+		if (que_.empty() && !notEmptyCond_.wait_until(g, absTime, [=]{return !que_.empty();}))
 			return false;
 		*val = std::move(que_.front());
 		que_.pop();
-		if (n == cap_) {
+		if (que_.size() == cap_-1) {
 			g.unlock();
 			notFullCond_.notify_one();
 		}
diff --git a/src/token.cpp b/src/token.cpp
index ffbf816..3853cf2 100644
--- a/src/token.cpp
+++ b/src/token.cpp
@@ -23,27 +23,6 @@
 
 #include <iostream>
 
-/////////////////////////////////////////////////////////////////////////////
-// Paho C logger
-
-enum LOG_LEVELS {
-	INVALID_LEVEL = -1,
-	TRACE_MAX = 1,
-	TRACE_MED,
-	TRACE_MIN,
-	TRACE_PROTOCOL,
-	LOG_PROTOCOL = TRACE_PROTOCOL,
-	LOG_ERROR,
-	LOG_SEVERE,
-	LOG_FATAL,
-};
-
-extern "C" {
-	void Log(enum LOG_LEVELS, int, const char *, ...);
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
 namespace mqtt {
 
 // --------------------------------------------------------------------------
@@ -110,8 +89,6 @@ void token::on_failure5(void* context, MQTTAsync_failureData5* rsp)
 //
 void token::on_success(MQTTAsync_successData* rsp)
 {
-	::Log(TRACE_MIN, -1, "[cpp] on_success");
-
 	unique_lock g(lock_);
 	iaction_listener* listener = listener_;
 
@@ -154,8 +131,6 @@ void token::on_success(MQTTAsync_successData* rsp)
 //
 void token::on_success5(MQTTAsync_successData5* rsp)
 {
-	::Log(TRACE_MIN, -1, "[cpp] on_success5");
-
 	unique_lock g(lock_);
 	iaction_listener* listener = listener_;
 	if (rsp) {
@@ -197,8 +172,6 @@ void token::on_success5(MQTTAsync_successData5* rsp)
 //
 void token::on_failure(MQTTAsync_failureData* rsp)
 {
-	::Log(TRACE_MIN, -1, "[cpp] on_failure");
-
 	unique_lock g(lock_);
 	iaction_listener* listener = listener_;
 	if (rsp) {
@@ -230,8 +203,6 @@ void token::on_failure(MQTTAsync_failureData* rsp)
 //
 void token::on_failure5(MQTTAsync_failureData5* rsp)
 {
-	::Log(TRACE_MIN, -1, "[cpp] on_failure5");
-
 	unique_lock g(lock_);
 	iaction_listener* listener = listener_;
 	if (rsp) {
