diff --git a/CMakeLists.txt b/CMakeLists.txt
index a91d2ed1b939cfc07fff50fb4a440169ede6d0ee..c7c6675448189312e529b1a4c05e574ed50df0d5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -244,7 +244,8 @@ set(COMMON_SOURCES
   ${APP_SRC_DIR}/messageparser.cpp
   ${APP_SRC_DIR}/previewengine.cpp
   ${APP_SRC_DIR}/imagedownloader.cpp
-  ${APP_SRC_DIR}/pluginversionmanager.cpp)
+  ${APP_SRC_DIR}/pluginversionmanager.cpp
+  ${APP_SRC_DIR}/connectioninfolistmodel.cpp)
 
 set(COMMON_HEADERS
   ${APP_SRC_DIR}/avatarimageprovider.h
@@ -310,8 +311,8 @@ set(COMMON_HEADERS
   ${APP_SRC_DIR}/messageparser.h
   ${APP_SRC_DIR}/htmlparser.h
   ${APP_SRC_DIR}/imagedownloader.h
-  ${APP_SRC_DIR}/pluginversionmanager.h)
-
+  ${APP_SRC_DIR}/pluginversionmanager.h
+  ${APP_SRC_DIR}/connectioninfolistmodel.h)
 
 # For libavutil/avframe.
 set(LIBJAMI_CONTRIB_DIR "${DAEMON_DIR}/contrib")
diff --git a/resources/icons/Connected_Black_24dp.svg b/resources/icons/Connected_Black_24dp.svg
new file mode 100644
index 0000000000000000000000000000000000000000..70325ffa54f31949e0a76b9be3fedc60cd8f9629
--- /dev/null
+++ b/resources/icons/Connected_Black_24dp.svg
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
+<path id="noun-connection-5025318" d="M18,6.3c1.2,0,2.2-1,2.2-2.1C20.1,3,19.2,2,18,2c-1.2,0-2.2,1-2.2,2.1c0,0.5,0.2,1.1,0.6,1.5
+	l-3.3,3.8c-0.8-0.6-2-0.5-2.7,0.2L7.3,7.1c0.5-0.8,0.2-1.9-0.6-2.4C5.9,4.2,4.8,4.5,4.3,5.3C3.8,6.1,4,7.2,4.9,7.7
+	C5.6,8.1,6.4,8,7,7.5l3.1,2.5c-0.5,0.8-0.4,1.9,0.3,2.6l-2.9,2.9c-1.1-0.7-2.5-0.4-3.2,0.7c-0.7,1.1-0.4,2.5,0.7,3.2
+	c1.1,0.7,2.5,0.4,3.2-0.7c0.6-0.9,0.5-2.1-0.3-2.9l2.9-2.9c0.3,0.2,0.7,0.3,1.2,0.3c0,0,0.1,0,0.1,0l0.8,4.8
+	c-1.1,0.3-1.7,1.4-1.4,2.5c0.3,1.1,1.4,1.7,2.5,1.4c1.1-0.3,1.7-1.4,1.4-2.5c-0.3-0.9-1-1.4-1.9-1.4c0,0-0.1,0-0.1,0l-0.8-4.8
+	c0.4-0.1,0.7-0.3,0.9-0.6l3.6,2.7c-0.4,0.8-0.2,1.8,0.6,2.2c0.8,0.4,1.8,0.2,2.2-0.6c0.4-0.8,0.2-1.8-0.6-2.2
+	c-0.6-0.4-1.4-0.3-1.9,0.2l-3.6-2.7c0.2-0.3,0.3-0.7,0.3-1.1c0-0.5-0.2-1.1-0.6-1.5l3.3-3.8C17.1,6.2,17.5,6.3,18,6.3L18,6.3z"/>
+</svg>
diff --git a/resources/icons/Connecting_Black_24dp.svg b/resources/icons/Connecting_Black_24dp.svg
new file mode 100644
index 0000000000000000000000000000000000000000..b35b6e7bc7225007ba29f5f2386bbe78f54c2208
--- /dev/null
+++ b/resources/icons/Connecting_Black_24dp.svg
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
+<g id="noun-waiting-3611673" transform="translate(-13.64 -30.48)">
+	<path id="Path_278" d="M25.9,34.5c0.5,0,0.8-0.4,0.8-0.8c0-0.5-0.4-0.8-0.8-0.8c-0.5,0-0.8,0.4-0.8,0.8c0,0.2,0.1,0.4,0.2,0.6
+		C25.4,34.4,25.6,34.5,25.9,34.5z"/>
+	<path id="Path_279" d="M32.7,36.9c0.4-0.4,0.4-1.1,0-1.5c-0.4-0.4-1.1-0.4-1.5,0c-0.4,0.4-0.4,1.1,0,1.5c0.2,0.2,0.5,0.3,0.8,0.3
+		C32.2,37.2,32.5,37.1,32.7,36.9z"/>
+	<path id="Path_280" d="M34.5,41c-0.7,0-1.2,0.5-1.2,1.2s0.5,1.2,1.2,1.2c0.7,0,1.2-0.5,1.2-1.2c0-0.3-0.1-0.6-0.3-0.8
+		C35.1,41.1,34.8,41,34.5,41z"/>
+	<path id="Path_281" d="M31.9,47c-0.7,0-1.3,0.6-1.3,1.3c0,0.7,0.6,1.3,1.3,1.3c0.7,0,1.3-0.6,1.3-1.3c0-0.3-0.1-0.7-0.4-0.9
+		C32.6,47.1,32.3,47,31.9,47z"/>
+	<path id="Path_282" d="M25.9,49.4c-0.8,0-1.4,0.6-1.4,1.4c0,0.8,0.6,1.4,1.4,1.4c0.8,0,1.4-0.6,1.4-1.4c0-0.4-0.1-0.7-0.4-1
+		C26.6,49.5,26.2,49.4,25.9,49.4z"/>
+	<path id="Path_283" d="M18.7,47.2L18.7,47.2c-0.6,0.6-0.6,1.6,0,2.2c0.6,0.6,1.6,0.6,2.2,0c0.6-0.6,0.6-1.6,0-2.2
+		c-0.3-0.3-0.7-0.5-1.1-0.5C19.4,46.7,19,46.9,18.7,47.2z"/>
+	<path id="Path_284" d="M18.9,42.2c0-0.9-0.7-1.7-1.6-1.7s-1.7,0.7-1.7,1.6c0,0.9,0.7,1.7,1.6,1.7c0.4,0,0.9-0.2,1.2-0.5
+		C18.8,43,18.9,42.6,18.9,42.2z"/>
+	<path id="Path_285" d="M21.1,34.9c-0.7-0.3-1.5-0.1-1.9,0.6c-0.3,0.7-0.1,1.5,0.6,1.9c0.7,0.3,1.5,0.1,1.9-0.6
+		c0.1-0.2,0.2-0.5,0.1-0.7C21.8,35.5,21.5,35.1,21.1,34.9z"/>
+</g>
+</svg>
diff --git a/src/app/connectioninfolistmodel.cpp b/src/app/connectioninfolistmodel.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..99f1a808b5aecb150aa80247d2abe1746ff2c1bd
--- /dev/null
+++ b/src/app/connectioninfolistmodel.cpp
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2023 Savoir-faire Linux Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "connectioninfolistmodel.h"
+
+ConnectionInfoListModel::ConnectionInfoListModel(LRCInstance* instance, QObject* parent)
+    : AbstractListModelBase(parent)
+{
+    lrcInstance_ = instance;
+    connect(lrcInstance_,
+            &LRCInstance::currentAccountIdChanged,
+            this,
+            &ConnectionInfoListModel::resetData);
+}
+
+int
+ConnectionInfoListModel::rowCount(const QModelIndex& parent) const
+{
+    return peerIds_.size();
+}
+
+QVariant
+ConnectionInfoListModel::data(const QModelIndex& index, int role) const
+{
+    const auto accountId = lrcInstance_->get_currentAccountId();
+
+    if (accountId.isEmpty()) {
+        qWarning() << "ConnectionInfoListModel::data: accountId or peerID is empty";
+        return {};
+    }
+    const auto peerId = peerIds_[index.row()];
+    const auto peerData = peerData_[peerId];
+
+    switch (role) {
+    case ConnectionInfoList::ChannelsMap: {
+        QVariantMap channelsMapMap;
+        int i = 0;
+        for (const auto& device : peerData.keys()) {
+            QString channelsId = peerData[device]["id"].toString();
+            QVariantMap channelsMap;
+            const auto channelInfoList = lrcInstance_->getChannelList(accountId, channelsId);
+            for (const auto& channelInfo : channelInfoList) {
+                channelsMap.insert(channelInfo["id"], channelInfo["name"]);
+            }
+            channelsMapMap.insert(QString::number(i++), channelsMap);
+        }
+        return QVariant(channelsMapMap);
+    }
+    case ConnectionInfoList::ConnectionDatas: {
+        QString peerString;
+        peerString += "Peer:" + peerId;
+        for (const auto& device : peerData.keys()) {
+            peerString += "{";
+            peerString += "Device:" + device + ",";
+            peerString += "Status:" + peerData[device]["status"].toString() + ",";
+            peerString += "Channels:" + peerData[device]["channels"].toString() + ",";
+            peerString += "Remote Address" + peerData[device]["remoteAddress"].toString();
+            peerString += "}";
+        }
+        return peerString;
+    }
+    case ConnectionInfoList::PeerId:
+        return peerId;
+    case ConnectionInfoList::RemoteAddress: {
+        QVariantMap remoteAddressMap;
+        int i = 0;
+        for (const auto& device : peerData.keys()) {
+            remoteAddressMap.insert(QString::number(i++), peerData[device]["remoteAddress"]);
+        }
+        return QVariant(remoteAddressMap);
+    }
+    case ConnectionInfoList::DeviceId: {
+        QVariantMap deviceMap;
+        int i = 0;
+        for (const auto& device : peerData.keys()) {
+            deviceMap.insert(QString::number(i++), device);
+        }
+        return QVariant(deviceMap);
+    }
+    case ConnectionInfoList::Status: {
+        QVariantMap statusMap;
+        int i = 0;
+        for (const auto& device : peerData.keys()) {
+            statusMap.insert(QString::number(i++), peerData[device]["status"]);
+        }
+        return QVariantMap(statusMap);
+    }
+    case ConnectionInfoList::Channels: {
+        QVariantMap channelsMap;
+        int i = 0;
+        for (const auto& device : peerData.keys()) {
+            channelsMap.insert(QString::number(i++), peerData[device]["channels"]);
+        }
+        return QVariant(channelsMap);
+    }
+    case ConnectionInfoList::Count:
+        return peerData.size();
+    }
+    return {};
+}
+
+QHash<int, QByteArray>
+ConnectionInfoListModel::roleNames() const
+{
+    using namespace ConnectionInfoList;
+    QHash<int, QByteArray> roles;
+#define X(role) roles[role] = #role;
+    CONNECTONINFO_ROLES
+#undef X
+    return roles;
+}
+
+void
+ConnectionInfoListModel::update()
+{
+    const auto accountId = lrcInstance_->get_currentAccountId();
+    if (accountId.isEmpty()) {
+        return;
+    }
+    aggregateData();
+}
+
+template<typename T>
+std::tuple<QVector<T>, QVector<T>>
+getSetDiff(QVector<T> u, QVector<T> v)
+{
+    using namespace std;
+    QVector<T> a, r;
+    set_difference(v.begin(), v.end(), u.begin(), u.end(), inserter(a, a.begin()));
+    set_difference(u.begin(), u.end(), v.begin(), v.end(), inserter(r, r.begin()));
+    return {a, r};
+}
+
+void
+ConnectionInfoListModel::aggregateData()
+{
+    const auto accountId = lrcInstance_->get_currentAccountId();
+    if (accountId.isEmpty()) {
+        return;
+    }
+
+    connectionInfoList_ = lrcInstance_->getConnectionList(accountId);
+
+    peerData_ = {};
+
+    QSet<QString> newPeerIds;
+
+    for (const auto& connectionInfo : connectionInfoList_) {
+        if (!connectionInfo["peer"].isEmpty()) {
+            newPeerIds.insert(connectionInfo["peer"]);
+        }
+        const auto channelInfoList = lrcInstance_->getChannelList(accountId, connectionInfo["id"]);
+        peerData_[connectionInfo["peer"]][connectionInfo["device"]] = {};
+        peerData_[connectionInfo["peer"]][connectionInfo["device"]]["status"]
+            = connectionInfo["status"];
+        peerData_[connectionInfo["peer"]][connectionInfo["device"]]["channels"] = channelInfoList
+                                                                                      .size();
+        peerData_[connectionInfo["peer"]][connectionInfo["device"]]["id"] = connectionInfo["id"];
+        peerData_[connectionInfo["peer"]][connectionInfo["device"]]["remoteAddress"]
+            = connectionInfo["remoteAddress"];
+    }
+
+    QVector<QString> oldVector;
+    for (const auto& peerId : peerIds_) {
+        oldVector << peerId;
+    }
+    QVector<QString> newVector;
+    for (const auto& peerId : newPeerIds) {
+        newVector << peerId;
+    }
+
+    std::sort(oldVector.begin(), oldVector.end());
+    std::sort(newVector.begin(), newVector.end());
+
+    QVector<QString> removed, added;
+    std::tie(added, removed) = getSetDiff(oldVector, newVector);
+    Q_FOREACH (const auto& key, added) {
+        auto index = std::distance(newVector.begin(),
+                                   std::find(newVector.begin(), newVector.end(), key));
+        beginInsertRows(QModelIndex(), index, index);
+        peerIds_.insert(index, key);
+        endInsertRows();
+    }
+    Q_FOREACH (const auto& key, removed) {
+        auto index = std::distance(oldVector.begin(),
+                                   std::find(oldVector.begin(), oldVector.end(), key));
+        beginRemoveRows(QModelIndex(), index, index);
+        if (peerIds_.size() > index) {
+            peerIds_.remove(index);
+        } else {
+            qWarning() << "ConnectionInfoListModel::aggregateData: index out of range";
+            qWarning() << "index: " << index;
+            qWarning() << "key: " << key;
+        }
+        endRemoveRows();
+    }
+
+    // HACK: loop through all the peerIds_ and update the data for each one.
+    // This is not efficient, but it works.
+    Q_FOREACH (const auto& peerId, peerIds_) {
+        auto index = std::distance(peerIds_.begin(),
+                                   std::find(peerIds_.begin(), peerIds_.end(), peerId));
+        Q_EMIT dataChanged(this->index(index), this->index(index));
+    }
+}
+
+void
+ConnectionInfoListModel::resetData()
+{
+    beginResetModel();
+    peerIds_.clear();
+    peerData_.clear();
+    endResetModel();
+}
\ No newline at end of file
diff --git a/src/app/connectioninfolistmodel.h b/src/app/connectioninfolistmodel.h
new file mode 100644
index 0000000000000000000000000000000000000000..74daa7a24b35b6f5f3fcbdee86212e854745340c
--- /dev/null
+++ b/src/app/connectioninfolistmodel.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2023 Savoir-faire Linux Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "abstractlistmodelbase.h"
+
+#define CONNECTONINFO_ROLES \
+    X(ConnectionDatas) \
+    X(ChannelsMap) \
+    X(PeerName) \
+    X(PeerId) \
+    X(DeviceId) \
+    X(Status) \
+    X(Channels) \
+    X(RemoteAddress) \
+    X(Count) // this is the number of connections (convenience)
+
+namespace ConnectionInfoList {
+Q_NAMESPACE
+enum Role {
+    DummyRole = Qt::UserRole + 1,
+#define X(role) role,
+    CONNECTONINFO_ROLES
+#undef X
+};
+Q_ENUM_NS(Role)
+} // namespace ConnectionInfoList
+
+class ConnectionInfoListModel : public AbstractListModelBase
+{
+public:
+    explicit ConnectionInfoListModel(LRCInstance* instance, QObject* parent = nullptr);
+
+    int rowCount(const QModelIndex& parent = QModelIndex()) const override;
+    QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
+    QHash<int, QByteArray> roleNames() const override;
+
+    Q_INVOKABLE void update();
+
+private:
+    using Role = ConnectionInfoList::Role;
+
+    VectorMapStringString connectionInfoList_;
+
+    QVector<QString> peerIds_;
+    QMap<QString, QMap<QString, QMap<QString, QVariant>>> peerData_;
+    void aggregateData();
+    void resetData();
+};
diff --git a/src/app/constant/JamiStrings.qml b/src/app/constant/JamiStrings.qml
index 6bec14fbfbe6272bfa5028e5b5e75531dd13968f..f3c9d145f2d3de4e5d18014feee1d724c9c4d821 100644
--- a/src/app/constant/JamiStrings.qml
+++ b/src/app/constant/JamiStrings.qml
@@ -850,4 +850,16 @@ Item {
     property string shiftEnter: qsTr("SHIFT+ENTER")
     property string textFormattingDescription: qsTr("ENTER or SHIFT+ENTER to insert a new line")
     property string textFormatting: qsTr("Text formatting")
+
+    //Connection monitoring
+    property string connected: qsTr("Connected")
+    property string connectingTLS: qsTr("Connecting TLS")
+    property string connectingICE: qsTr("Connecting ICE")
+    property string connecting: qsTr("Connecting")
+    property string waiting: qsTr("Waiting")
+    property string contact: qsTr("Contact")
+    property string connection: qsTr("Connection")
+    property string channels: qsTr("Channels")
+    property string copyAllData: qsTr("Copy all data")
+    property string remote: qsTr("Remote: ")
 }
diff --git a/src/app/constant/JamiTheme.qml b/src/app/constant/JamiTheme.qml
index e29815fdc896c9213c5c111c4f9bcba5b42f2974..ed15e162da0b23463d7f5b8b2664436f78a1dcd0 100644
--- a/src/app/constant/JamiTheme.qml
+++ b/src/app/constant/JamiTheme.qml
@@ -664,6 +664,11 @@ Item {
     property color donationBackgroundColor: "#D5E4EF"
     property string donationUrl: "https://jami.net/donate/"
 
+    //Connection monitoring
+    property color connectionMonitoringTableColor1: "#f0efef"
+    property color connectionMonitoringTableColor2: "#f6f5f5"
+    property color connectionMonitoringHeaderColor: "#d1d1d1"
+
     function setTheme(dark) {
         darkTheme = dark;
     }
diff --git a/src/app/contactadapter.cpp b/src/app/contactadapter.cpp
index fb49f41da9d6f0235d1faa44e5a3e6a0e684ad83..7585f346616e4cea0c3c579684575c798894dcb7 100644
--- a/src/app/contactadapter.cpp
+++ b/src/app/contactadapter.cpp
@@ -21,10 +21,16 @@
 #include "contactadapter.h"
 
 #include "lrcinstance.h"
+#include "qmlregister.h"
 
 ContactAdapter::ContactAdapter(LRCInstance* instance, QObject* parent)
     : QmlAdapterBase(instance, parent)
+    , connectionInfoListModel_(new ConnectionInfoListModel(lrcInstance_, this))
 {
+    QML_REGISTERSINGLETONTYPE_POBJECT(NS_MODELS,
+                                      connectionInfoListModel_.get(),
+                                      "ConnectionInfoListModel");
+
     selectableProxyModel_.reset(new SelectableProxyModel(this));
     if (lrcInstance_) {
         connectSignals();
@@ -246,6 +252,12 @@ ContactAdapter::removeContact(const QString& peerUri, bool banContact)
     accInfo.contactModel->removeContact(peerUri, banContact);
 }
 
+void
+ContactAdapter::updateConnectionInfo()
+{
+    connectionInfoListModel_->update();
+}
+
 void
 ContactAdapter::connectSignals()
 {
diff --git a/src/app/contactadapter.h b/src/app/contactadapter.h
index c3666eec3eaf0504766a883eb5bf11b79e9c5b55..ca92a6690fe2967f61b2c817e68014df67c1da37 100644
--- a/src/app/contactadapter.h
+++ b/src/app/contactadapter.h
@@ -21,6 +21,7 @@
 #include "qmladapterbase.h"
 #include "smartlistmodel.h"
 #include "conversationlistmodel.h"
+#include "connectioninfolistmodel.h"
 
 #include <QObject>
 #include <QSortFilterProxyModel>
@@ -90,6 +91,7 @@ public:
     Q_INVOKABLE void setSearchFilter(const QString& filter);
     Q_INVOKABLE void contactSelected(int index);
     Q_INVOKABLE void removeContact(const QString& peerUri, bool banContact);
+    Q_INVOKABLE void updateConnectionInfo();
 
     void connectSignals();
 
@@ -104,6 +106,7 @@ private:
     SmartListModel::Type listModeltype_;
     QScopedPointer<SmartListModel> smartListModel_;
     QScopedPointer<SelectableProxyModel> selectableProxyModel_;
+    QScopedPointer<ConnectionInfoListModel> connectionInfoListModel_;
 
     QStringList defaultModerators_;
 
diff --git a/src/app/lrcinstance.cpp b/src/app/lrcinstance.cpp
index 02bafe4fdf91bc6cffb85a64aafa705ac1d3c432..0cd74c325f797be8fda559246db9c21a0cefe948 100644
--- a/src/app/lrcinstance.cpp
+++ b/src/app/lrcinstance.cpp
@@ -458,3 +458,15 @@ LRCInstance::set_selectedConvUid(QString selectedConvUid)
         Q_EMIT selectedConvUidChanged();
     }
 }
+
+VectorMapStringString
+LRCInstance::getConnectionList(const QString& accountId, const QString& uid)
+{
+    return Lrc::getConnectionList(accountId, uid);
+}
+
+VectorMapStringString
+LRCInstance::getChannelList(const QString& accountId, const QString& uid)
+{
+    return Lrc::getChannelList(accountId, uid);
+}
\ No newline at end of file
diff --git a/src/app/lrcinstance.h b/src/app/lrcinstance.h
index 08075930d35e241a3e1b351bc3152b2c958891ef..502165c3fe0188f2cd9dcc9b587f9e9c1afdadd9 100644
--- a/src/app/lrcinstance.h
+++ b/src/app/lrcinstance.h
@@ -135,6 +135,10 @@ public:
         return debugMode_;
     }
 
+    VectorMapStringString getConnectionList(const QString& accountId, const QString& uid = {});
+
+    VectorMapStringString getChannelList(const QString& accountId, const QString& uid = {});
+
 Q_SIGNALS:
     void accountListChanged();
     void selectedConvUidChanged();
diff --git a/src/app/settingsview/components/ChannelsPopup.qml b/src/app/settingsview/components/ChannelsPopup.qml
new file mode 100644
index 0000000000000000000000000000000000000000..4ef7ffa3192c606987999d851d3a9318425bb1f9
--- /dev/null
+++ b/src/app/settingsview/components/ChannelsPopup.qml
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2023 Savoir-faire Linux Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+import QtQuick
+import QtQuick.Controls
+import Qt5Compat.GraphicalEffects
+import QtQuick.Layouts
+import net.jami.Models 1.1
+import net.jami.Adapters 1.1
+import net.jami.Constants 1.1
+
+Popup {
+    id: popup
+    width: textComponent.contentWidth + 40 < popup.maxWidth - 20 ? textComponent.contentWidth + 40 : popup.maxWidth - 20
+    height: textComponent.contentHeight + 40 < 350 ? textComponent.contentHeight + 40 : 350
+    property string text: ""
+    property int maxWidth: 0
+    x: -1 * (popup.width - 20)
+
+    Rectangle {
+        anchors.fill: parent
+        color: JamiTheme.transparentColor
+
+        Flickable {
+            anchors.fill: parent
+            contentHeight: textComponent.contentHeight + 10
+            contentWidth: textComponent.contentWidth + 20
+            clip: true
+            ScrollBar.vertical: ScrollBar {
+                active: contentHeight > height
+            }
+            ScrollBar.horizontal: ScrollBar {
+                active: contentWidth > width
+            }
+            contentX: 10
+            contentY: 10
+
+            Text {
+                id: textComponent
+                width: popup.maxWidth - 20
+                elide: Text.ElideRight
+                horizontalAlignment: Text.AlignLeft
+                text: popup.text
+            }
+        }
+    }
+}
diff --git a/src/app/settingsview/components/ConnectionMonitoringTable.qml b/src/app/settingsview/components/ConnectionMonitoringTable.qml
new file mode 100644
index 0000000000000000000000000000000000000000..c770495f3eae71a2bef42fc1b6872c1e72858844
--- /dev/null
+++ b/src/app/settingsview/components/ConnectionMonitoringTable.qml
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2023 Savoir-faire Linux Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import net.jami.Adapters 1.1
+import net.jami.Constants 1.1
+import net.jami.Enums 1.1
+import net.jami.Models 1.1
+import "../../commoncomponents"
+import "../js/logviewwindowcreation.js" as LogViewWindowCreation
+
+ListView {
+    id: listview
+    height: contentItem.childrenRect.height
+    anchors.top: parent.top
+    anchors.topMargin: 10
+
+    spacing: 5
+    cacheBuffer: 10
+
+    property int rota: 0
+
+    header: Rectangle {
+        height: 55
+        width: connectionMonitoringTable.width
+        Rectangle {
+            color: JamiTheme.connectionMonitoringHeaderColor
+            anchors.top: parent.top
+            height: 50
+            width: connectionMonitoringTable.width
+
+            RowLayout {
+                anchors.fill: parent
+                Rectangle {
+                    id: profile
+                    height: 50
+                    Layout.leftMargin: 5
+                    Layout.preferredWidth: 210
+                    color: JamiTheme.transparentColor
+                    Text {
+                        id: textImage
+                        anchors.leftMargin: 10
+                        anchors.verticalCenter: parent.verticalCenter
+                        text: JamiStrings.contact
+                    }
+                }
+
+                Rectangle {
+                    id: device
+                    Layout.fillWidth: true
+                    height: 50
+                    color: JamiTheme.transparentColor
+                    Text {
+                        id: deviceText
+                        anchors.verticalCenter: parent.verticalCenter
+                        text: JamiStrings.device
+                    }
+                }
+
+                Rectangle {
+                    id: connection
+                    width: 130
+                    height: 50
+                    radius: 5
+                    color: JamiTheme.transparentColor
+                    Text {
+                        id: connectionText
+                        anchors.verticalCenter: parent.verticalCenter
+                        anchors.leftMargin: 10
+                        text: JamiStrings.connection
+                    }
+                }
+
+                Rectangle {
+                    id: channel
+                    height: 50
+                    width: 70
+                    color: JamiTheme.transparentColor
+                    Text {
+                        anchors.verticalCenter: parent.verticalCenter
+                        text: JamiStrings.channels
+                    }
+                }
+            }
+        }
+    }
+
+    model: ConnectionInfoListModel
+    Timer {
+        interval: 1000
+        running: root.visible
+        repeat: true
+        onTriggered: {
+            ContactAdapter.updateConnectionInfo();
+            listview.rota = listview.rota + 5;
+        }
+    }
+
+    delegate: Rectangle {
+        id: delegate
+        height: Count == 0 ? 0 : 10 + 40 * Count
+        width: connectionMonitoringTable.width
+        color: index % 2 === 0 ? JamiTheme.connectionMonitoringTableColor1 : JamiTheme.connectionMonitoringTableColor2
+
+        ListView {
+            id: listView2
+            height: 40 * Count
+
+            anchors.top: delegate.top
+
+            spacing: 0
+
+            model: Count
+
+            delegate: RowLayout {
+                id: rowLayoutDelegate
+                height: 40
+                width: connectionMonitoringTable.width
+
+                Rectangle {
+                    id: profile
+                    height: 50
+                    Layout.leftMargin: 5
+                    Layout.preferredWidth: 210
+                    color: JamiTheme.transparentColor
+                    Avatar {
+                        id: avatar
+                        visible: index == 0
+                        anchors.left: parent.left
+                        height: 40
+                        width: 40
+                        anchors.verticalCenter: parent.verticalCenter
+                        imageId: PeerId
+                        mode: Avatar.Mode.Contact
+                    }
+                    Rectangle {
+                        id: usernameRect
+                        anchors.left: avatar.right
+                        anchors.verticalCenter: parent.verticalCenter
+                        width: profile.width - 50
+                        height: 40
+                        color: JamiTheme.transparentColor
+
+                        Rectangle {
+                            id: usernameRect2
+                            visible: index == 0
+                            width: profile.width - 50
+                            height: 20
+                            anchors.leftMargin: 10
+                            anchors.top: parent.top
+                            anchors.left: parent.left
+                            color: JamiTheme.transparentColor
+
+                            Text {
+                                id: usernameText
+                                text: UtilsAdapter.getBestNameForUri(CurrentAccount.id, PeerId)
+                                elide: Text.ElideRight
+                            }
+                        }
+
+                        Rectangle {
+                            width: profile.width - 50
+                            height: 20
+                            anchors.leftMargin: 10
+                            anchors.top: usernameRect2.bottom
+                            anchors.left: parent.left
+                            visible: usernameRect2.visible && (UtilsAdapter.getBestIdForUri(CurrentAccount.id, PeerId) != UtilsAdapter.getBestNameForUri(CurrentAccount.id, PeerId))
+                            color: JamiTheme.transparentColor
+
+                            Text {
+                                id: idText
+                                anchors.fill: parent
+                                text: UtilsAdapter.getBestIdForUri(CurrentAccount.id, PeerId)
+                                font.pixelSize: 12
+                                font.underline: usernameText.font.underline
+                                elide: Text.ElideRight
+                            }
+                        }
+
+                        MouseArea {
+                            anchors.fill: parent
+                            hoverEnabled: true
+                            onEntered: {
+                                usernameText.font.underline = true;
+                                tooltipContact.text = JamiStrings.copyAllData;
+                            }
+                            onExited: {
+                                usernameText.font.underline = false;
+                                tooltipContact.text = JamiStrings.copyAllData;
+                            }
+
+                            ToolTip {
+                                id: tooltipContact
+                                visible: usernameText.font.underline
+                                text: JamiStrings.copyAllData
+                            }
+                            onClicked: {
+                                tooltipContact.text = JamiStrings.logsViewCopied;
+                                UtilsAdapter.setClipboardText(ConnectionDatas);
+                            }
+                        }
+                    }
+                }
+
+                Rectangle {
+                    height: 40
+                    Layout.fillWidth: true
+                    color: delegate.color
+                    Text {
+                        id: delegateDeviceText
+                        anchors.verticalCenter: parent.verticalCenter
+                        anchors.left: parent.left
+                        text: {
+                            if (DeviceId[index] != undefined) {
+                                return DeviceId[index];
+                            } else {
+                                return "";
+                            }
+                        }
+                        elide: Text.ElideMiddle
+                        width: parent.width - 10
+                        MouseArea {
+                            anchors.fill: parent
+                            hoverEnabled: true
+                            onEntered: {
+                                delegateDeviceText.font.underline = true;
+                            }
+                            onExited: {
+                                delegateDeviceText.font.underline = false;
+                                tooltipDevice.text = delegateDeviceText.text;
+                            }
+
+                            ToolTip {
+                                id: tooltipDevice
+                                visible: delegateDeviceText.font.underline
+                                text: delegateDeviceText.text
+                            }
+                            onClicked: {
+                                tooltipDevice.text = delegateDeviceText.text + " (" + JamiStrings.logsViewCopied + ")";
+                                UtilsAdapter.setClipboardText(delegateDeviceText.text);
+                            }
+                        }
+                    }
+                }
+
+                Rectangle {
+                    id: connectionRectangle
+                    color: delegate.color
+                    height: 40
+                    Layout.preferredWidth: 130
+                    property var status: Status[index]
+                    ResponsiveImage {
+                        id: connectionImage
+                        anchors.left: parent.left
+                        anchors.verticalCenter: parent.verticalCenter
+                        rotation: connectionRectangle.status == 0 ? 0 : listview.rota
+                        source: {
+                            if (connectionRectangle.status == 0) {
+                                return JamiResources.connected_black_24dp_svg;
+                            } else {
+                                return JamiResources.connecting_black_24dp_svg;
+                            }
+                        }
+                        color: {
+                            if (connectionRectangle.status == 0) {
+                                return "#009c7f";
+                            } else {
+                                if (connectionRectangle.status == 4) {
+                                    return "red";
+                                } else {
+                                    return "#ff8100";
+                                }
+                            }
+                        }
+                    }
+                    Text {
+                        id: connectionText
+                        anchors.left: connectionImage.right
+                        anchors.verticalCenter: parent.verticalCenter
+                        anchors.leftMargin: 5
+                        text: if (connectionRectangle.status == 0) {
+                            return JamiStrings.connected;
+                        } else {
+                            if (connectionRectangle.status == 1) {
+                                return JamiStrings.connectingTLS;
+                            } else {
+                                if (connectionRectangle.status == 2) {
+                                    return JamiStrings.connectingICE;
+                                } else {
+                                    if (connectionRectangle.status == 3) {
+                                        return JamiStrings.connecting;
+                                    } else {
+                                        return JamiStrings.waiting;
+                                    }
+                                }
+                            }
+                        }
+                        color: connectionImage.color
+                        property var tooltipText: JamiStrings.remote + RemoteAddress[index]
+                        MouseArea {
+                            anchors.fill: parent
+                            hoverEnabled: true
+                            onEntered: {
+                                connectionText.font.underline = true;
+                            }
+                            onExited: {
+                                connectionText.font.underline = false;
+                            }
+
+                            ToolTip {
+                                visible: connectionText.font.underline
+                                text: connectionText.tooltipText
+                            }
+                        }
+                    }
+                }
+
+                Rectangle {
+                    id: channelDelegateRectangle
+                    height: 40
+                    Layout.preferredWidth: 70
+                    color: delegate.color
+                    Text {
+                        id: channelText
+                        anchors.verticalCenter: parent.verticalCenter
+                        anchors.leftMargin: 10
+                        anchors.left: parent.left
+                        text: {
+                            if (Channels[index] != undefined) {
+                                return Channels[index];
+                            } else {
+                                return "";
+                            }
+                        }
+                        MouseArea {
+                            anchors.fill: parent
+                            hoverEnabled: true
+
+                            onExited: {
+                                channelText.font.underline = false;
+                            }
+
+                            onEntered: {
+                                channelText.font.underline = true;
+                            }
+
+                            onClicked: {
+                                var output = "";
+                                var channelMap = ChannelsMap[index];
+                                for (var key in channelMap) {
+                                    var value = channelMap[key];
+                                    var keyHexa = parseInt(key, 16).toString();
+                                    output += keyHexa + " : " + value + "\n";
+                                }
+                                viewCoordinator.presentDialog(parent, "settingsview/components/ChannelsPopup.qml", {
+                                        "text": output,
+                                        "maxWidth": connectionMonitoringTable.width
+                                    });
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/src/app/settingsview/components/SettingsPageBase.qml b/src/app/settingsview/components/SettingsPageBase.qml
index 69cab4ac7a84ca35ab0e8dbc83d22ae59c535306..cc982f3866b55616dfc6fc9f648a5fc697b8586f 100644
--- a/src/app/settingsview/components/SettingsPageBase.qml
+++ b/src/app/settingsview/components/SettingsPageBase.qml
@@ -27,6 +27,7 @@ JamiSplitView {
     id: root
     required property Item flickableContent
     property real contentFlickableWidth: Math.min(JamiTheme.maximumWidthSettingsView, settingsPage.width - 2 * JamiTheme.preferredSettingsMarginSize)
+    property real tableWidth: Math.min(JamiTheme.maximumWidthSettingsView * 2, settingsPage.width - 2 * JamiTheme.preferredSettingsMarginSize)
     property alias title: settingsPage.title
     property color backgroundColor: JamiTheme.secondaryBackgroundColor
     property alias pageContainer: settingsPage
diff --git a/src/app/settingsview/components/TroubleshootSettingsPage.qml b/src/app/settingsview/components/TroubleshootSettingsPage.qml
index 63f5adedc6b21571ee317943372cad9ef6f73125..6e1be6d4bdd0301da022db130d5d9f8aa2daa4b0 100644
--- a/src/app/settingsview/components/TroubleshootSettingsPage.qml
+++ b/src/app/settingsview/components/TroubleshootSettingsPage.qml
@@ -29,11 +29,18 @@ import "../js/logviewwindowcreation.js" as LogViewWindowCreation
 SettingsPageBase {
     id: root
 
+    Layout.fillWidth: true
+
+    readonly property string baseProviderPrefix: 'image://avatarImage'
+
+    property string typePrefix: 'contact'
+    property string divider: '_'
+
     property int itemWidth
 
     title: JamiStrings.troubleshootTitle
 
-    flickableContent: ColumnLayout {
+    flickableContent: Column {
         id: troubleshootSettingsColumnLayout
 
         width: contentFlickableWidth
@@ -42,7 +49,7 @@ SettingsPageBase {
         anchors.leftMargin: JamiTheme.preferredSettingsMarginSize
 
         RowLayout {
-
+            id: rawLayout
             Text {
                 Layout.fillWidth: true
                 Layout.preferredHeight: 30
@@ -85,5 +92,15 @@ SettingsPageBase {
                 }
             }
         }
+
+        Rectangle {
+            id: connectionMonitoringTable
+            height: listview.childrenRect.height + 60
+            width: tableWidth
+
+            ConnectionMonitoringTable {
+                id: listview
+            }
+        }
     }
 }
diff --git a/src/libclient/api/lrc.h b/src/libclient/api/lrc.h
index 1151c0bee614f0cd22091df19bb99fdc23e9787e..03c61727ce052030438f2178a2ec10cb9e66c2ed 100644
--- a/src/libclient/api/lrc.h
+++ b/src/libclient/api/lrc.h
@@ -109,6 +109,16 @@ public:
      */
     static VectorString getConferences(const QString& accountId = "");
 
+    /**
+     * Get connection list from daemon
+     */
+    static VectorMapStringString getConnectionList(const QString& accountId, const QString& uid);
+
+    /**
+     * Get channel list from daemon
+     */
+    static VectorMapStringString getChannelList(const QString& accountId, const QString& uid);
+
     /**
      * Preference
      */
diff --git a/src/libclient/lrc.cpp b/src/libclient/lrc.cpp
index c2fb60af0b6051e159e54c3eabd14e4ac8862ec9..330b94750ae9d8029cf9347c21897ca22019abec 100644
--- a/src/libclient/lrc.cpp
+++ b/src/libclient/lrc.cpp
@@ -211,6 +211,18 @@ Lrc::getConferences(const QString& accountId)
     return result;
 }
 
+VectorMapStringString
+Lrc::getConnectionList(const QString& accountId, const QString& uid)
+{
+    return ConfigurationManager::instance().getConnectionList(accountId, uid);
+}
+
+VectorMapStringString
+Lrc::getChannelList(const QString& accountId, const QString& uid)
+{
+    return ConfigurationManager::instance().getChannelList(accountId, uid);
+}
+
 bool
 isFinished(const QString& callState)
 {
diff --git a/src/libclient/qtwrapper/configurationmanager_wrap.h b/src/libclient/qtwrapper/configurationmanager_wrap.h
index 2eb19ef9ca49015e362518cf2870e46ff4cd8915..2ecafd2a214b49ac91735c8754833d1abf51dd96 100644
--- a/src/libclient/qtwrapper/configurationmanager_wrap.h
+++ b/src/libclient/qtwrapper/configurationmanager_wrap.h
@@ -1016,6 +1016,24 @@ public Q_SLOTS: // METHODS
         libjami::setAllModerators(accountID.toStdString(), allModerators);
     }
 
+    VectorMapStringString getConnectionList(const QString& accountId, const QString& uid)
+    {
+        VectorMapStringString temp;
+        for (auto x : libjami::getConnectionList(accountId.toStdString(), uid.toStdString())) {
+            temp.push_back(convertMap(x));
+        }
+        return temp;
+    }
+
+    VectorMapStringString getChannelList(const QString& accountId, const QString& uid)
+    {
+        VectorMapStringString temp;
+        for (auto x : libjami::getChannelList(accountId.toStdString(), uid.toStdString())) {
+            temp.push_back(convertMap(x));
+        }
+        return temp;
+    }
+
     bool isAllModerators(const QString& accountID)
     {
         return libjami::isAllModerators(accountID.toStdString());