diff --git a/xwiki-platform-core/xwiki-platform-rendering/xwiki-platform-rendering-async/xwiki-platform-rendering-async-default/src/main/java/org/xwiki/rendering/async/internal/AsyncRendererCache.java b/xwiki-platform-core/xwiki-platform-rendering/xwiki-platform-rendering-async/xwiki-platform-rendering-async-default/src/main/java/org/xwiki/rendering/async/internal/AsyncRendererCache.java
index c5b5be3ec4f..91f350d9626 100644
--- a/xwiki-platform-core/xwiki-platform-rendering/xwiki-platform-rendering-async/xwiki-platform-rendering-async-default/src/main/java/org/xwiki/rendering/async/internal/AsyncRendererCache.java
+++ b/xwiki-platform-core/xwiki-platform-rendering/xwiki-platform-rendering-async/xwiki-platform-rendering-async-default/src/main/java/org/xwiki/rendering/async/internal/AsyncRendererCache.java
@@ -19,15 +19,19 @@
  */
 package org.xwiki.rendering.async.internal;
 
+import java.io.Serializable;
 import java.lang.reflect.Type;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
+import javax.servlet.http.HttpSession;
 
 import org.xwiki.cache.Cache;
 import org.xwiki.cache.CacheEntry;
@@ -45,6 +49,8 @@
 import org.xwiki.rendering.async.internal.DefaultAsyncContext.RightEntry;
 import org.xwiki.security.authorization.AuthorizationManager;
 
+import com.xpn.xwiki.internal.context.SerializableHttpSessionWrapper;
+
 /**
  * Share cache containing the results of the {@link AsyncRenderer} executions.
  * 
@@ -73,6 +79,8 @@
 
     private final Map<RightEntry, Set<String>> rightMapping = new ConcurrentHashMap<>();
 
+    private final Map<String, Set<String>> sessionMapping = new ConcurrentHashMap<>();
+
     private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
 
     /**
@@ -212,6 +220,11 @@ public void cacheEntryAdded(CacheEntryEvent<AsyncRendererJobStatus> event)
         for (RightEntry right : status.getRights()) {
             this.rightMapping.computeIfAbsent(right, k -> ConcurrentHashMap.newKeySet()).add(key);
         }
+
+        Optional<String> sessionId = getSessionId(status);
+        if (sessionId.isPresent()) {
+            this.sessionMapping.computeIfAbsent(sessionId.get(), k -> ConcurrentHashMap.newKeySet()).add(key);
+        }
     }
 
     @Override
@@ -225,6 +238,25 @@ public void cacheEntryRemoved(CacheEntryEvent<AsyncRendererJobStatus> event)
         remove(key, status.getRoleTypes(), this.roleTypeMapping);
         remove(key, status.getRoles(), this.roleMapping);
         remove(key, status.getRights(), this.rightMapping);
+        remove(key, getSessionId(status).map(Collections::singleton).orElse(Collections.emptySet()),
+            this.sessionMapping);
+    }
+
+    private Optional<String> getSessionId(AsyncRendererJobStatus status)
+    {
+        Map<String, Serializable> context = status.getRequest().getContext();
+        if (context != null) {
+            SerializableHttpSessionWrapper sessionWrapper =
+                (SerializableHttpSessionWrapper) context.get("request.session");
+            if (sessionWrapper != null) {
+                HttpSession session = sessionWrapper.getSession();
+                if (session != null) {
+                    return Optional.ofNullable(session.getId());
+                }
+            }
+        }
+
+        return Optional.empty();
     }
 
     private <T> void remove(String key, Set<T> values, Map<T, Set<String>> mapping)
@@ -304,6 +336,19 @@ private void checkRight(RightEntry right, Set<String> keys)
         }
     }
 
+    /**
+     * Clean entries associated to the specified session.
+     * 
+     * @param sessionId the session identifier
+     * @since 14.10.18
+     * @since 15.5.3
+     * @since 15.9RC1
+     */
+    public void cleanCacheForSession(String sessionId)
+    {
+        clean(this.sessionMapping.remove(sessionId));
+    }
+
     /**
      * @param keys the keys of the cache entries to remove
      */
diff --git a/xwiki-platform-core/xwiki-platform-rendering/xwiki-platform-rendering-async/xwiki-platform-rendering-async-default/src/main/java/org/xwiki/rendering/async/internal/AsyncRendererCacheListener.java b/xwiki-platform-core/xwiki-platform-rendering/xwiki-platform-rendering-async/xwiki-platform-rendering-async-default/src/main/java/org/xwiki/rendering/async/internal/AsyncRendererCacheListener.java
index f8408e48c64..33f0e7c4617 100644
--- a/xwiki-platform-core/xwiki-platform-rendering/xwiki-platform-rendering-async/xwiki-platform-rendering-async-default/src/main/java/org/xwiki/rendering/async/internal/AsyncRendererCacheListener.java
+++ b/xwiki-platform-core/xwiki-platform-rendering/xwiki-platform-rendering-async/xwiki-platform-rendering-async-default/src/main/java/org/xwiki/rendering/async/internal/AsyncRendererCacheListener.java
@@ -23,6 +23,7 @@
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
+import javax.servlet.http.HttpSession;
 
 import org.xwiki.bridge.event.DocumentCreatedEvent;
 import org.xwiki.bridge.event.DocumentDeletedEvent;
@@ -32,6 +33,7 @@
 import org.xwiki.component.event.ComponentDescriptorAddedEvent;
 import org.xwiki.component.event.ComponentDescriptorEvent;
 import org.xwiki.component.event.ComponentDescriptorRemovedEvent;
+import org.xwiki.container.servlet.events.SessionDestroyedEvent;
 import org.xwiki.model.reference.WikiReference;
 import org.xwiki.observation.AbstractEventListener;
 import org.xwiki.observation.EventListener;
@@ -78,7 +80,7 @@ public AsyncRendererCacheListener()
             new XClassPropertyUpdatedEvent(), new XObjectAddedEvent(), new XObjectDeletedEvent(),
             new XObjectUpdatedEvent(), new DocumentCreatedEvent(), new DocumentUpdatedEvent(),
             new DocumentDeletedEvent(), new ComponentDescriptorAddedEvent(), new ComponentDescriptorRemovedEvent(),
-            new RightUpdatedEvent());
+            new RightUpdatedEvent(), new SessionDestroyedEvent());
     }
 
     @Override
@@ -93,6 +95,9 @@ public void onEvent(Event event, Object source, Object data)
             WikiReference wikiReference = new WikiReference(((WikiDeletedEvent) event).getWikiId());
 
             this.cache.cleanCache(wikiReference.getName());
+        } else if (event instanceof SessionDestroyedEvent) {
+            // Clean entries associated to the current session.
+            this.cache.cleanCacheForSession(((HttpSession) source).getId());
         } else {
             XWikiDocument document = (XWikiDocument) source;
 
diff --git a/xwiki-platform-core/xwiki-platform-rendering/xwiki-platform-rendering-async/xwiki-platform-rendering-async-default/src/test/java/org/xwiki/rendering/async/internal/AsyncRendererCacheTest.java b/xwiki-platform-core/xwiki-platform-rendering/xwiki-platform-rendering-async/xwiki-platform-rendering-async-default/src/test/java/org/xwiki/rendering/async/internal/AsyncRendererCacheTest.java
index 9a81d294584..36b88972dd2 100644
--- a/xwiki-platform-core/xwiki-platform-rendering/xwiki-platform-rendering-async/xwiki-platform-rendering-async-default/src/test/java/org/xwiki/rendering/async/internal/AsyncRendererCacheTest.java
+++ b/xwiki-platform-core/xwiki-platform-rendering/xwiki-platform-rendering-async/xwiki-platform-rendering-async-default/src/test/java/org/xwiki/rendering/async/internal/AsyncRendererCacheTest.java
@@ -19,13 +19,17 @@
  */
 package org.xwiki.rendering.async.internal;
 
+import java.io.Serializable;
 import java.lang.reflect.Type;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import javax.servlet.http.HttpSession;
+
 import org.apache.commons.lang3.reflect.FieldUtils;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -45,6 +49,8 @@
 import org.xwiki.test.junit5.mockito.InjectMockComponents;
 import org.xwiki.test.junit5.mockito.MockComponent;
 
+import com.xpn.xwiki.internal.context.SerializableHttpSessionWrapper;
+
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertSame;
@@ -120,6 +126,13 @@ private void setRights(RightEntry... rights)
         this.status.setRights(Set.of(rights));
     }
 
+    private void setSession(HttpSession session)
+    {
+        Map<String, Serializable> context = new HashMap<>();
+        context.put("request.session", new SerializableHttpSessionWrapper(session));
+        this.status.getRequest().setContext(context);
+    }
+
     private List<String> getId()
     {
         return this.status.getRequest().getId();
@@ -217,6 +230,27 @@ void invalidateSyncOnWiki()
         assertNull(this.asyncCache.getSync(getId()));
     }
 
+    @Test
+    void invalidateSyncOnSession()
+    {
+        HttpSession session = mock(HttpSession.class);
+        when(session.getId()).thenReturn("test session");
+
+        setSession(session);
+
+        this.asyncCache.put(this.status);
+
+        assertSame(this.status, this.asyncCache.getSync(getId()));
+
+        this.asyncCache.cleanCacheForSession("other session");
+
+        assertSame(this.status, this.asyncCache.getSync(getId()));
+
+        this.asyncCache.cleanCacheForSession("test session");
+
+        assertNull(this.asyncCache.getSync(getId()));
+    }
+
     @Test
     void invalidateSyncOnRight() throws IllegalAccessException
     {
