diff --git a/src/dbus/qdbusconnection_p.h b/src/dbus/qdbusconnection_p.h
index b733a688563ce0841591fafa3cf3d5c66e34270e..fff9f29b0318c5d3eacc566941b12b47ec3036f5 100644
--- a/src/dbus/qdbusconnection_p.h
+++ b/src/dbus/qdbusconnection_p.h
@@ -254,7 +254,7 @@ private:
                      const QVector<int> &metaTypes, int slotIdx);
 
     SignalHookHash::Iterator removeSignalHookNoLock(SignalHookHash::Iterator it);
-    void disconnectObjectTree(ObjectTreeNode &node);
+    void collectAllObjects(ObjectTreeNode &node, QSet<QObject *> &set);
 
     bool isServiceRegisteredByThread(const QString &serviceName);
 
diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp
index d0468f4af0eb2ee02634281d6feb7982184623f2..147966b9b094814016b418cbb5880db2148b1135 100644
--- a/src/dbus/qdbusintegrator.cpp
+++ b/src/dbus/qdbusintegrator.cpp
@@ -1071,17 +1071,18 @@ QDBusConnectionPrivate::~QDBusConnectionPrivate()
     }
 }
 
-void QDBusConnectionPrivate::disconnectObjectTree(QDBusConnectionPrivate::ObjectTreeNode &haystack)
+void QDBusConnectionPrivate::collectAllObjects(QDBusConnectionPrivate::ObjectTreeNode &haystack,
+                                               QSet<QObject *> &set)
 {
     QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator it = haystack.children.begin();
 
     while (it != haystack.children.end()) {
-        disconnectObjectTree(*it);
+        collectAllObjects(*it, set);
         it++;
     }
 
     if (haystack.obj)
-        haystack.obj->disconnect(this);
+        set.insert(haystack.obj);
 }
 
 void QDBusConnectionPrivate::closeConnection()
@@ -1110,15 +1111,23 @@ void QDBusConnectionPrivate::closeConnection()
 
     // Disconnect all signals from signal hooks and from the object tree to
     // avoid QObject::destroyed being sent to dbus daemon thread which has
-    // already quit.
-    SignalHookHash::iterator sit = signalHooks.begin();
-    while (sit != signalHooks.end()) {
-        sit.value().obj->disconnect(this);
-        sit++;
+    // already quit. We need to make sure we disconnect exactly once per
+    // object, because if we tried a second time, we might be hitting a
+    // dangling pointer.
+    QSet<QObject *> allObjects;
+    collectAllObjects(rootNode, allObjects);
+    SignalHookHash::const_iterator sit = signalHooks.constBegin();
+    while (sit != signalHooks.constEnd()) {
+        allObjects.insert(sit.value().obj);
+        ++sit;
+    }
+
+    // now disconnect ourselves
+    QSet<QObject *>::const_iterator oit = allObjects.constBegin();
+    while (oit != allObjects.constEnd()) {
+        (*oit)->disconnect(this);
+        ++oit;
     }
-
-    disconnectObjectTree(rootNode);
-    rootNode.children.clear();  // free resources
 }
 
 void QDBusConnectionPrivate::handleDBusDisconnection()