diff --git a/changelog.d/4612.misc b/changelog.d/4612.misc
new file mode 100644
index 0000000000..43b5007b7e
--- /dev/null
+++ b/changelog.d/4612.misc
@@ -0,0 +1 @@
+Workaround to fetch all the pending toDevice events from a Synapse homeserver
\ No newline at end of file
diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt
index 3faa0c9488..fe8f55c4cb 100644
--- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt
@@ -30,6 +30,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow
 import kotlinx.coroutines.flow.SharedFlow
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.runBlocking
+import org.matrix.android.sdk.api.extensions.orFalse
 import org.matrix.android.sdk.api.failure.Failure
 import org.matrix.android.sdk.api.failure.isTokenError
 import org.matrix.android.sdk.api.logger.LoggerTag
@@ -71,6 +72,7 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask,
     private var isStarted = false
     private var isTokenValid = true
     private var retryNoNetworkTask: TimerTask? = null
+    private var previousSyncResponseHasToDevice = false
 
     private val activeCallListObserver = Observer<MutableList<MxCall>> { activeCalls ->
         if (activeCalls.isEmpty() && backgroundDetectionObserver.isInBackground) {
@@ -172,11 +174,16 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask,
                     updateStateTo(SyncState.Running(afterPause = true))
                 }
                 // No timeout after a pause
-                val timeout = state.let { if (it is SyncState.Running && it.afterPause) 0 else DEFAULT_LONG_POOL_TIMEOUT }
+                val timeout = when {
+                    previousSyncResponseHasToDevice                        -> 0L
+                            .also { Timber.tag(loggerTag.value).d("Force timeout to 0") }
+                    state.let { it is SyncState.Running && it.afterPause } -> 0L
+                    else                                                   -> DEFAULT_LONG_POOL_TIMEOUT
+                }
                 Timber.tag(loggerTag.value).d("Execute sync request with timeout $timeout")
                 val params = SyncTask.Params(timeout, SyncPresence.Online)
                 val sync = syncScope.launch {
-                    doSync(params)
+                    previousSyncResponseHasToDevice = doSync(params)
                 }
                 runBlocking {
                     sync.join()
@@ -203,10 +210,14 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask,
         }
     }
 
-    private suspend fun doSync(params: SyncTask.Params) {
-        try {
+    /**
+     * Will return true if the sync response contains some toDevice events.
+     */
+    private suspend fun doSync(params: SyncTask.Params): Boolean {
+        return try {
             val syncResponse = syncTask.execute(params)
             _syncFlow.emit(syncResponse)
+            syncResponse.toDevice?.events?.isNotEmpty().orFalse()
         } catch (failure: Throwable) {
             if (failure is Failure.NetworkConnection) {
                 canReachServer = false
@@ -229,6 +240,7 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask,
                     delay(RETRY_WAIT_TIME_MS)
                 }
             }
+            false
         } finally {
             state.let {
                 if (it is SyncState.Running && it.afterPause) {