diff --git a/bin/dbus/cx.ring.Ring.ConfigurationManager.xml b/bin/dbus/cx.ring.Ring.ConfigurationManager.xml
index 2de4955e3fe187706c243ecf54a4f4e0dcc7fc83..a992463dc66e20edefc2fd65f43c0885d0cc233c 100644
--- a/bin/dbus/cx.ring.Ring.ConfigurationManager.xml
+++ b/bin/dbus/cx.ring.Ring.ConfigurationManager.xml
@@ -542,6 +542,16 @@
           </arg>
        </method>
 
+      <method name="cancelMessage" tp:name-for-bindings="cancelMessage">
+          <arg type="s" name="accountID" direction="in"/>
+          <arg type="t" name="id" direction="in"/>
+          <arg type="b" name="success" direction="out">
+             <tp:docstring>
+               Cancel pending message.
+             </tp:docstring>
+          </arg>
+       </method>
+
        <method name="getLastMessages" tp:name-for-bindings="getLastMessages">
            <arg type="s" name="accountID" direction="in"/>
            <arg type="t" name="base_timestamp" direction="in"/>
diff --git a/bin/jni/configurationmanager.i b/bin/jni/configurationmanager.i
index 0d5200f8b28cb40e63dbf42e91eabdd71bca1f82..08767ec252a0579a8d38d9b4c91cd53510533146 100644
--- a/bin/jni/configurationmanager.i
+++ b/bin/jni/configurationmanager.i
@@ -89,6 +89,8 @@ void registerAllAccounts(void);
 uint64_t sendAccountTextMessage(const std::string& accountID, const std::string& to, const std::map<std::string, std::string>& message);
 std::vector<DRing::Message> getLastMessages(const std::string& accountID, uint64_t base_timestamp);
 int getMessageStatus(uint64_t id);
+int getMessageStatus(const std::string& accountID, uint64_t id);
+bool cancelMessage(const std::string& accountID, uint64_t id);
 
 bool lookupName(const std::string& account, const std::string& nameserver, const std::string& name);
 bool lookupAddress(const std::string& account, const std::string& nameserver, const std::string& address);
diff --git a/bin/nodejs/configurationmanager.i b/bin/nodejs/configurationmanager.i
index 17deafcf1fd98c1f3f171a9aa9ecd73afe57b566..aee3d5e4a1c24678329b6240daccee18d03d79b6 100644
--- a/bin/nodejs/configurationmanager.i
+++ b/bin/nodejs/configurationmanager.i
@@ -85,6 +85,8 @@ void registerAllAccounts(void);
 uint64_t sendAccountTextMessage(const std::string& accountID, const std::string& to, const std::map<std::string, std::string>& message);
 std::vector<Message> getLastMessages(const std::string& accountID, const uint64_t& base_timestamp);
 int getMessageStatus(uint64_t id);
+int getMessageStatus(const std::string& accountID, uint64_t id);
+bool cancelMessage(const std::string& accountID, uint64_t id);
 
 bool lookupName(const std::string& account, const std::string& nameserver, const std::string& name);
 bool lookupAddress(const std::string& account, const std::string& nameserver, const std::string& address);
diff --git a/configure.ac b/configure.ac
index fc7ec1326f1f1b6b3d38151c21815ce8bec58d15..599f604b31997216f1081be0b67a70726bc7eca7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@ dnl Jami - configure.ac for automake 1.9 and autoconf 2.59
 
 dnl Process this file with autoconf to produce a configure script.
 AC_PREREQ([2.65])
-AC_INIT([Jami Daemon],[7.5.0],[ring@gnu.org],[jami])
+AC_INIT([Jami Daemon],[7.6.0],[ring@gnu.org],[jami])
 
 AC_COPYRIGHT([[Copyright (c) Savoir-faire Linux 2004-2019]])
 AC_REVISION([$Revision$])
diff --git a/src/account.h b/src/account.h
index 89d489712678ab6f3c6e5fb9e6cd00a8624d20f3..429bc542a648dd590f2e964190a1f10e590a62c4 100644
--- a/src/account.h
+++ b/src/account.h
@@ -163,10 +163,14 @@ class Account : public Serializable, public std::enable_shared_from_this<Account
         /**
          * Return the status corresponding to the token.
          */
-        virtual im::MessageStatus getMessageStatus(uint64_t id UNUSED) const {
+        virtual im::MessageStatus getMessageStatus(uint64_t /*id*/) const {
             return im::MessageStatus::UNKNOWN;
         }
 
+        virtual bool cancelMessage(uint64_t /*id*/) {
+            return false;
+        }
+
         std::vector<std::shared_ptr<Call>> getCalls();
 
         /**
diff --git a/src/client/configurationmanager.cpp b/src/client/configurationmanager.cpp
index d3bae8c0b3635eda15ac337261a4411f87aae844..77fd50d8898aa132726fe889d72543986a4fedb9 100644
--- a/src/client/configurationmanager.cpp
+++ b/src/client/configurationmanager.cpp
@@ -265,13 +265,29 @@ sendAccountTextMessage(const std::string& accountID, const std::string& to, cons
 std::vector<Message>
 getLastMessages(const std::string& accountID, const uint64_t& base_timestamp)
 {
-    return ring::Manager::instance().getLastMessages(accountID, base_timestamp);
+    if (const auto acc = ring::Manager::instance().getAccount(accountID))
+        return acc->getLastMessages(base_timestamp);
+    return {};
+}
+
+int
+getMessageStatus(uint64_t messageId)
+{
+    return ring::Manager::instance().getMessageStatus(messageId);
 }
 
 int
-getMessageStatus(uint64_t id)
+getMessageStatus(const std::string& accountID, uint64_t messageId)
 {
-    return ring::Manager::instance().getMessageStatus(id);
+    return ring::Manager::instance().getMessageStatus(accountID, messageId);
+}
+
+bool
+cancelMessage(const std::string& accountID, uint64_t messageId)
+{
+    if (const auto acc = ring::Manager::instance().getAccount(accountID))
+        return acc->cancelMessage(messageId);
+    return {};
 }
 
 bool
diff --git a/src/dring/account_const.h b/src/dring/account_const.h
index 00925b77ac37903429079c3ac3854312ba58bbd4..4c9f9646b1d002ce03b7320a9b0951ed22aec703 100644
--- a/src/dring/account_const.h
+++ b/src/dring/account_const.h
@@ -67,7 +67,8 @@ enum class MessageStates : int {
     SENDING,
     SENT,
     READ,
-    FAILURE
+    FAILURE,
+    CANCELLED
 }; //DRing::Account::MessageStates
 
 enum class testAccountICEInitializationStatus : int {
diff --git a/src/dring/configurationmanager_interface.h b/src/dring/configurationmanager_interface.h
index 813b6dd0460608c6a2f7f11d4dc4ad0d1bc63dc5..e760b5ea486552769ebab263cfbd4400e1256433 100644
--- a/src/dring/configurationmanager_interface.h
+++ b/src/dring/configurationmanager_interface.h
@@ -75,9 +75,10 @@ DRING_PUBLIC std::vector<std::string> getAccountList();
 DRING_PUBLIC void sendRegister(const std::string& accountID, bool enable);
 DRING_PUBLIC void registerAllAccounts(void);
 DRING_PUBLIC uint64_t sendAccountTextMessage(const std::string& accountID, const std::string& to, const std::map<std::string, std::string>& payloads);
+DRING_PUBLIC bool cancelMessage(const std::string& accountID, uint64_t message);
 DRING_PUBLIC std::vector<Message> getLastMessages(const std::string& accountID, const uint64_t& base_timestamp);
 DRING_PUBLIC int getMessageStatus(uint64_t id);
-
+DRING_PUBLIC int getMessageStatus(const std::string& accountID, uint64_t id);
 
 DRING_PUBLIC std::map<std::string, std::string> getTlsDefaultSettings();
 
diff --git a/src/im/message_engine.cpp b/src/im/message_engine.cpp
index cd6236245154dda098c0580e46c74d40af4e12f1..a3661f754da73f71585354a007b0b320c35ab81c 100644
--- a/src/im/message_engine.cpp
+++ b/src/im/message_engine.cpp
@@ -116,6 +116,25 @@ MessageEngine::getStatus(MessageToken t) const
     return MessageStatus::UNKNOWN;
 }
 
+bool
+MessageEngine::cancel(MessageToken t)
+{
+    std::lock_guard<std::mutex> lock(messagesMutex_);
+    for (auto& p : messages_) {
+        auto m = p.second.find(t);
+        if (m != p.second.end()) {
+            m->second.status = MessageStatus::CANCELLED;
+            emitSignal<DRing::ConfigurationSignal::AccountMessageStatusChanged>(account_.getAccountID(),
+                                                                            t,
+                                                                            m->second.to,
+                                                                            static_cast<int>(DRing::Account::MessageStates::CANCELLED));
+            save_();
+            return true;
+        }
+    }
+    return false;
+}
+
 void
 MessageEngine::onMessageSent(const std::string& peer, MessageToken token, bool ok)
 {
@@ -215,7 +234,7 @@ MessageEngine::save_() const
             Json::Value peerRoot(Json::objectValue);
             for (auto& m : c.second) {
                 auto& v = m.second;
-                if (v.status == MessageStatus::FAILURE || v.status == MessageStatus::SENT)
+                if (v.status == MessageStatus::FAILURE || v.status == MessageStatus::SENT || v.status == MessageStatus::CANCELLED)
                     continue;
                 Json::Value msg;
                 std::ostringstream msgsId;
diff --git a/src/im/message_engine.h b/src/im/message_engine.h
index 353c5ad59a29c7ccb4cf0789cc134a4328189ada..c68bf0eb27927289aaff9c9559c5ea8f22b0408b 100644
--- a/src/im/message_engine.h
+++ b/src/im/message_engine.h
@@ -40,7 +40,8 @@ enum class MessageStatus {
     SENDING,
     SENT,
     READ,
-    FAILURE
+    FAILURE,
+    CANCELLED
 };
 
 class MessageEngine
@@ -53,6 +54,8 @@ public:
 
     MessageStatus getStatus(MessageToken t) const;
 
+    bool cancel(MessageToken t);
+
     bool isSent(MessageToken t) const {
         return getStatus(t) == MessageStatus::SENT;
     }
diff --git a/src/manager.cpp b/src/manager.cpp
index 9344bba7f97937f455aa8e799990c85426d1dbad..84af6c6cd24466a25b125b8f94a7e99ecfac6c21 100644
--- a/src/manager.cpp
+++ b/src/manager.cpp
@@ -3027,30 +3027,42 @@ Manager::sendTextMessage(const std::string& accountID, const std::string& to,
 }
 
 int
-Manager::getMessageStatus(uint64_t id)
+statusFromImStatus(im::MessageStatus status) {
+    switch (status) {
+    case im::MessageStatus::IDLE:
+    case im::MessageStatus::SENDING:
+        return static_cast<int>(DRing::Account::MessageStates::SENDING);
+    case im::MessageStatus::SENT:
+        return static_cast<int>(DRing::Account::MessageStates::SENT);
+    case im::MessageStatus::READ:
+        return static_cast<int>(DRing::Account::MessageStates::READ);
+    case im::MessageStatus::FAILURE:
+        return static_cast<int>(DRing::Account::MessageStates::FAILURE);
+    default:
+        return static_cast<int>(DRing::Account::MessageStates::UNKNOWN);
+    }
+}
+
+int
+Manager::getMessageStatus(uint64_t id) const
 {
     const auto& allAccounts = accountFactory.getAllAccounts();
     for (auto acc : allAccounts) {
         auto status = acc->getMessageStatus(id);
-        if (status != im::MessageStatus::UNKNOWN) {
-            switch (status) {
-            case im::MessageStatus::IDLE:
-            case im::MessageStatus::SENDING:
-                return static_cast<int>(DRing::Account::MessageStates::SENDING);
-            case im::MessageStatus::SENT:
-                return static_cast<int>(DRing::Account::MessageStates::SENT);
-            case im::MessageStatus::READ:
-                return static_cast<int>(DRing::Account::MessageStates::READ);
-            case im::MessageStatus::FAILURE:
-                return static_cast<int>(DRing::Account::MessageStates::FAILURE);
-            default:
-                return static_cast<int>(DRing::Account::MessageStates::UNKNOWN);
-            }
-        }
+        if (status != im::MessageStatus::UNKNOWN)
+            return statusFromImStatus(status);
     }
     return static_cast<int>(DRing::Account::MessageStates::UNKNOWN);
 }
 
+int
+Manager::getMessageStatus(const std::string& accountID, uint64_t id) const
+{
+    if (const auto acc = getAccount(accountID))
+        return statusFromImStatus(acc->getMessageStatus(id));
+    return static_cast<int>(DRing::Account::MessageStates::UNKNOWN);
+}
+
 void
 Manager::setAccountActive(const std::string& accountID, bool active)
 {
diff --git a/src/manager.h b/src/manager.h
index f50bf67c21ee353542a897eab5595c5d3c44d8c4..083d22eedf48c280f01cefd34a4b6dfbe5055066 100644
--- a/src/manager.h
+++ b/src/manager.h
@@ -388,7 +388,8 @@ class Manager {
         uint64_t sendTextMessage(const std::string& accountID, const std::string& to,
                              const std::map<std::string, std::string>& payloads);
 
-        int getMessageStatus(uint64_t id);
+        int getMessageStatus(uint64_t id) const;
+        int getMessageStatus(const std::string& accountID, uint64_t id) const;
 
         /**
          * Get account list
diff --git a/src/sip/sipaccountbase.h b/src/sip/sipaccountbase.h
index f822357986a6ae547c0884f6bcb8b410eedb7127..2ebcdbe8e080069526468c1868a5e1dcdae475c3 100644
--- a/src/sip/sipaccountbase.h
+++ b/src/sip/sipaccountbase.h
@@ -268,6 +268,10 @@ public:
         return messageEngine_.getStatus(id);
     }
 
+    virtual bool cancelMessage(uint64_t id) override {
+        return messageEngine_.cancel(id);
+    }
+
     void onTextMessage(const std::string& from, const std::map<std::string, std::string>& payloads);
 
     /* Returns true if the username and/or hostname match this account */