diff --git a/src/generic_io.h b/src/generic_io.h
index 6f67b24eab1ef6f0419b5f7be9da2ba84a21316a..4147959c92759ec40f7eb78ccbad72a25174200f 100644
--- a/src/generic_io.h
+++ b/src/generic_io.h
@@ -20,6 +20,8 @@
 
 #pragma once
 
+#include "ip_utils.h"
+
 #include <functional>
 #include <vector>
 #include <system_error>
@@ -100,6 +102,16 @@ public:
         return res;
     }
 
+    /// Return the local IP address if known.
+    /// \note The address is not valid (addr.isUnspecified() returns true) if it's not known
+    /// or not available.
+    virtual IpAddr localAddr() const { return {}; }
+
+    /// Return the remote IP address if known.
+    /// \note The address is not valid (addr.isUnspecified() returns true) if it's not known
+    /// or not available.
+    virtual IpAddr remoteAddr() const { return {}; }
+
 protected:
     GenericSocket() = default;
 };
diff --git a/src/ice_socket.h b/src/ice_socket.h
index a61413aca030be254b8f4b03b32ccdb03797c1e9..b05ae3f6a05f04e84cf61cc9a0150786df009bd5 100644
--- a/src/ice_socket.h
+++ b/src/ice_socket.h
@@ -87,6 +87,10 @@ public:
 
     void setOnRecv(RecvCb&& cb) override;
 
+    IpAddr localAddr() const override;
+
+    IpAddr remoteAddr() const override;
+
 private:
     const int compId_;
     std::shared_ptr<IceTransport> ice_;
diff --git a/src/ice_transport.cpp b/src/ice_transport.cpp
index a7fdf5e0de43461926ee1fff255f719c81b40f40..4e02c26378a1e5b83f989b26a30ca9a0eb8f7850 100644
--- a/src/ice_transport.cpp
+++ b/src/ice_transport.cpp
@@ -1226,6 +1226,18 @@ IceSocketTransport::read(ValueType* buf, std::size_t len, std::error_code& ec)
     return res;
 }
 
+IpAddr
+IceSocketTransport::localAddr() const
+{
+    return ice_->getLocalAddress(compId_);
+}
+
+IpAddr
+IceSocketTransport::remoteAddr() const
+{
+    return ice_->getRemoteAddress(compId_);
+}
+
 //==============================================================================
 
 void
diff --git a/src/security/tls_session.cpp b/src/security/tls_session.cpp
index b336a4366f462fea77f5a55543f013b3e765ec22..eaee14128bbf6986a06b1d58adb6bba4ab1d2033 100644
--- a/src/security/tls_session.cpp
+++ b/src/security/tls_session.cpp
@@ -68,6 +68,7 @@ static constexpr auto HEARTBEAT_RETRANS_TIMEOUT = std::chrono::milliseconds(700)
 static constexpr auto HEARTBEAT_TOTAL_TIMEOUT = HEARTBEAT_RETRANS_TIMEOUT * HEARTBEAT_TRIES; // gnutls heartbeat time limit for heartbeat procedure (in milliseconds)
 static constexpr int MISS_ORDERING_LIMIT = 32; // maximal accepted distance of out-of-order packet (note: must be a signed type)
 static constexpr auto RX_OOO_TIMEOUT = std::chrono::milliseconds(1500);
+static constexpr int ASYMETRIC_TRANSPORT_MTU_OFFSET = 20; // when client, if your local IP is IPV4 and server is IPV6; you must reduce your MTU to avoid packet too big error on server side. the offset is the difference in size of IP headers
 
 // Helper to cast any duration into an integer number of milliseconds
 template <class Rep, class Period>
@@ -923,13 +924,26 @@ TlsSession::TlsSessionImpl::pathMtuHeartbeat()
                                   HEARTBEAT_TOTAL_TIMEOUT.count());
 
     int errno_send = GNUTLS_E_SUCCESS;
+    int mtuOffset = 0;
+
+    // when the remote (server) has a IPV6 interface selected by ICE, and local (client) has a IPV4 selected,
+    // the path MTU discovery triggers errors for packets too big on server side because of different IP headers overhead.
+    // Hence we have to signal to the TLS session to reduce the MTU on client size accordingly.
+    if (transport_.localAddr().isIpv4() and transport_.remoteAddr().isIpv6()) {
+        mtuOffset = ASYMETRIC_TRANSPORT_MTU_OFFSET;
+        RING_WARN() << "[TLS] local/remote IP protocol version not alike, use an MTU offset of "
+                    << ASYMETRIC_TRANSPORT_MTU_OFFSET << " bytes to compensate";
+    }
+
     mtuProbe_ = MTUS_[0];
+
     for (auto mtu: MTUS_) {
         gnutls_dtls_set_mtu(session_, mtu);
         auto data_mtu = gnutls_dtls_get_data_mtu(session_);
         RING_DBG() << "[TLS] PMTUD: mtu " << mtu
                    << ", payload " << data_mtu;
-        auto bytesToSend = data_mtu - 3; // want to know why -3? ask gnutls!
+        auto bytesToSend = data_mtu - mtuOffset - 3; // want to know why -3? ask gnutls!
+
         do {
             errno_send = gnutls_heartbeat_ping(session_, bytesToSend, HEARTBEAT_TRIES, GNUTLS_HEARTBEAT_WAIT);
         } while (errno_send == GNUTLS_E_AGAIN || errno_send == GNUTLS_E_INTERRUPTED);