diff --git a/bigbluebutton-html5/imports/api/meetings/server/modifiers/meetingHasEnded.js b/bigbluebutton-html5/imports/api/meetings/server/modifiers/meetingHasEnded.js
index 4448dc1908b13e6b6023d0faedbaa3f1b5d27dd6..7651b0fd5b6cfdde951d668b40f88ccc6705de7c 100755
--- a/bigbluebutton-html5/imports/api/meetings/server/modifiers/meetingHasEnded.js
+++ b/bigbluebutton-html5/imports/api/meetings/server/modifiers/meetingHasEnded.js
@@ -28,6 +28,8 @@ import clearRecordMeeting from './clearRecordMeeting';
 import clearVoiceCallStates from '/imports/api/voice-call-states/server/modifiers/clearVoiceCallStates';
 import clearVideoStreams from '/imports/api/video-streams/server/modifiers/clearVideoStreams';
 import clearAuthTokenValidation from '/imports/api/auth-token-validation/server/modifiers/clearAuthTokenValidation';
+import clearUsersPersistentData from '/imports/api/users-persistent-data/server/modifiers/clearUsersPersistentData';
+
 import clearWhiteboardMultiUser from '/imports/api/whiteboard-multi-user/server/modifiers/clearWhiteboardMultiUser';
 import Metrics from '/imports/startup/server/metrics';
 
@@ -62,6 +64,7 @@ export default function meetingHasEnded(meetingId) {
     clearAuthTokenValidation(meetingId);
     clearWhiteboardMultiUser(meetingId);
     clearScreenshare(meetingId);
+    clearUsersPersistentData(meetingId);
     BannedUsers.delete(meetingId);
     Metrics.removeMeeting(meetingId);
 
diff --git a/bigbluebutton-html5/imports/api/users-persistent-data/index.js b/bigbluebutton-html5/imports/api/users-persistent-data/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..ab5a6d5337560ae656d97ac8359e48b7f07268f4
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users-persistent-data/index.js
@@ -0,0 +1,9 @@
+import { Meteor } from 'meteor/meteor';
+
+const UsersPersistentData = new Mongo.Collection('users-persistent-data');
+
+if (Meteor.isServer) {
+  UsersPersistentData._ensureIndex({ meetingId: 1, userId: 1 });
+}
+
+export default UsersPersistentData;
diff --git a/bigbluebutton-html5/imports/api/users-persistent-data/server/index.js b/bigbluebutton-html5/imports/api/users-persistent-data/server/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..f7744b2befe8082e50007a8b8ebb3926b7e8a88a
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users-persistent-data/server/index.js
@@ -0,0 +1 @@
+import './publishers';
diff --git a/bigbluebutton-html5/imports/api/users-persistent-data/server/modifiers/addUserPersistentData.js b/bigbluebutton-html5/imports/api/users-persistent-data/server/modifiers/addUserPersistentData.js
new file mode 100644
index 0000000000000000000000000000000000000000..224fdeda73fedc9b4c2d7bcbef6f51ff1a0fb804
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users-persistent-data/server/modifiers/addUserPersistentData.js
@@ -0,0 +1,76 @@
+import { check } from 'meteor/check';
+import UsersPersistentData from '/imports/api/users-persistent-data';
+import Logger from '/imports/startup/server/logger';
+
+export default function addUserPersistentData(user) {
+  check(user, {
+    meetingId: String,
+    sortName: String,
+    color: String,
+    mobile: Boolean,
+    breakoutProps: Object,
+    inactivityCheck: Boolean,
+    responseDelay: Number,
+    loggedOut: Boolean,
+    intId: String,
+    extId: String,
+    name: String,
+    role: String,
+    guest: Boolean,
+    authed: Boolean,
+    guestStatus: String,
+    emoji: String,
+    presenter: Boolean,
+    locked: Boolean,
+    avatar: String,
+    clientType: String,
+    effectiveConnectionType: null,
+  });
+
+
+  const {
+    intId,
+    extId,
+    meetingId,
+    name,
+    role,
+    token,
+    avatar,
+    guest,
+    color,
+  } = user;
+
+  const userData = {
+    userId: intId,
+    extId,
+    meetingId,
+    name,
+    role,
+    token,
+    avatar,
+    guest,
+    color,
+    loggedOut: false,
+  };
+
+  const selector = {
+    userId: intId,
+    meetingId,
+  };
+
+  const modifier = {
+    $set: userData,
+  };
+
+  try {
+    const { insertedId } = UsersPersistentData.upsert(selector, modifier);
+
+    if (insertedId) {
+      Logger.info(`Added user id=${intId} to user persistent Data: meeting=${meetingId}`);
+    } else {
+      Logger.info(`Upserted user id=${intId} to user persistent Data: meeting=${meetingId}`);
+    }
+  } catch (err) {
+    Logger.error(`Adding note to the collection: ${err}`);
+  }
+}
diff --git a/bigbluebutton-html5/imports/api/users-persistent-data/server/modifiers/clearUsersPersistentData.js b/bigbluebutton-html5/imports/api/users-persistent-data/server/modifiers/clearUsersPersistentData.js
new file mode 100644
index 0000000000000000000000000000000000000000..4a5283c7e0dba7e6125942ba826dee23f602b7cf
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users-persistent-data/server/modifiers/clearUsersPersistentData.js
@@ -0,0 +1,26 @@
+import Logger from '/imports/startup/server/logger';
+import UsersPersistentData from '/imports/api/users-persistent-data/index';
+
+export default function clearUsersPersistentData(meetingId) {
+  if (meetingId) {
+    try {
+      const numberAffected = UsersPersistentData.remove({ meetingId });
+
+      if (numberAffected) {
+        Logger.info(`Cleared users persistent data (${meetingId})`);
+      }
+    } catch (err) {
+      Logger.error(`Error clearing users persistent data (${meetingId}). ${err}`);
+    }
+  } else {
+    try {
+      const numberAffected = UsersPersistentData.remove({});
+
+      if (numberAffected) {
+        Logger.info('Cleared users persistent data (all)');
+      }
+    } catch (err) {
+      Logger.error(`Error clearing users persistent data (all). ${err}`);
+    }
+  }
+}
diff --git a/bigbluebutton-html5/imports/api/users-persistent-data/server/modifiers/setloggedOutStatus.js b/bigbluebutton-html5/imports/api/users-persistent-data/server/modifiers/setloggedOutStatus.js
new file mode 100644
index 0000000000000000000000000000000000000000..7fb65739a9217a9431040e44366af389f4c63944
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users-persistent-data/server/modifiers/setloggedOutStatus.js
@@ -0,0 +1,26 @@
+import { check } from 'meteor/check';
+import UsersPersistentData from '/imports/api/users-persistent-data';
+import Logger from '/imports/startup/server/logger';
+
+export default function setloggedOutStatus(userId, meetingId, status = true) {
+  check(userId, String);
+  check(meetingId, String);
+  check(status, Boolean);
+
+  const selector = {
+    userId,
+    meetingId,
+  };
+
+  const modifier = {
+    $set: {
+      loggedOut: status,
+    },
+  };
+
+  try {
+    UsersPersistentData.update(selector, modifier);
+  } catch (err) {
+    Logger.error(`Adding note to the collection: ${err}`);
+  }
+}
diff --git a/bigbluebutton-html5/imports/api/users-persistent-data/server/publishers.js b/bigbluebutton-html5/imports/api/users-persistent-data/server/publishers.js
new file mode 100644
index 0000000000000000000000000000000000000000..3a05cb45059f6b5c102d2b7e963c78dab54f593b
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/users-persistent-data/server/publishers.js
@@ -0,0 +1,33 @@
+import UsersPersistentData from '/imports/api/users-persistent-data';
+import { Meteor } from 'meteor/meteor';
+import { extractCredentials } from '/imports/api/common/server/helpers';
+import { check } from 'meteor/check';
+
+function usersPersistentData() {
+  if (!this.userId) {
+    return UsersPersistentData.find({ meetingId: '' });
+  }
+  const { meetingId, requesterUserId } = extractCredentials(this.userId);
+
+  check(meetingId, String);
+  check(requesterUserId, String);
+
+  const selector = {
+    meetingId,
+  };
+
+  const options = {
+    fields: {
+      meetingId: false,
+    },
+  };
+
+  return UsersPersistentData.find(selector, options);
+}
+
+function publishUsersPersistentData(...args) {
+  const boundUsers = usersPersistentData.bind(this);
+  return boundUsers(...args);
+}
+
+Meteor.publish('users-persistent-data', publishUsersPersistentData);
diff --git a/bigbluebutton-html5/imports/api/users/server/modifiers/addUser.js b/bigbluebutton-html5/imports/api/users/server/modifiers/addUser.js
index d40b5f3874199708295f8b7b20dd77743f5bb406..6229deeb9dfd3911b68353d00c7915a051ef6967 100755
--- a/bigbluebutton-html5/imports/api/users/server/modifiers/addUser.js
+++ b/bigbluebutton-html5/imports/api/users/server/modifiers/addUser.js
@@ -5,7 +5,7 @@ import Meetings from '/imports/api/meetings';
 import VoiceUsers from '/imports/api/voice-users/';
 import _ from 'lodash';
 import SanitizeHTML from 'sanitize-html';
-
+import addUserPsersistentData from '/imports/api/users-persistent-data/server/modifiers/addUserPersistentData';
 import stringHash from 'string-hash';
 import flat from 'flat';
 
@@ -58,26 +58,28 @@ export default function addUser(meetingId, userData) {
     from a list based on the userId */
   const color = COLOR_LIST[stringHash(user.intId) % COLOR_LIST.length];
 
-  const modifier = {
-    $set: Object.assign(
-      {
-        meetingId,
-        sortName: user.name.trim().toLowerCase(),
-        color,
-        mobile: false,
-        breakoutProps: {
-          isBreakoutUser: Meeting.meetingProp.isBreakout,
-          parentId: Meeting.breakoutProps.parentId,
-        },
-        effectiveConnectionType: null,
-        inactivityCheck: false,
-        responseDelay: 0,
-        loggedOut: false,
+  const userInfos = Object.assign(
+    {
+      meetingId,
+      sortName: user.name.trim().toLowerCase(),
+      color,
+      mobile: false,
+      breakoutProps: {
+        isBreakoutUser: Meeting.meetingProp.isBreakout,
+        parentId: Meeting.breakoutProps.parentId,
       },
-      flat(user),
-    ),
-  };
+      effectiveConnectionType: null,
+      inactivityCheck: false,
+      responseDelay: 0,
+      loggedOut: false,
+    },
+    flat(user),
+  );
 
+  const modifier = {
+    $set: userInfos,
+  };
+  addUserPsersistentData(userInfos);
   // Only add an empty VoiceUser if there isn't one already and if the user coming in isn't a
   // dial-in user. We want to avoid overwriting good data
   if (user.clientType !== 'dial-in-user' && !VoiceUsers.findOne({ meetingId, intId: userId })) {
diff --git a/bigbluebutton-html5/imports/api/users/server/modifiers/removeUser.js b/bigbluebutton-html5/imports/api/users/server/modifiers/removeUser.js
index 48e005873d09cb61a4126f9de45e1b1b48f0c3f3..37af85aec7a2243d8dbf4069e309be211d623b72 100755
--- a/bigbluebutton-html5/imports/api/users/server/modifiers/removeUser.js
+++ b/bigbluebutton-html5/imports/api/users/server/modifiers/removeUser.js
@@ -2,6 +2,7 @@ import { check } from 'meteor/check';
 import Users from '/imports/api/users';
 import VideoStreams from '/imports/api/video-streams';
 import Logger from '/imports/startup/server/logger';
+import setloggedOutStatus from '/imports/api/users-persistent-data/server/modifiers/setloggedOutStatus';
 import stopWatchingExternalVideoSystemCall from '/imports/api/external-videos/server/methods/stopWatchingExternalVideoSystemCall';
 import clearUserInfoForRequester from '/imports/api/users-infos/server/modifiers/clearUserInfoForRequester';
 import ClientConnections from '/imports/startup/server/ClientConnections';
@@ -32,6 +33,7 @@ export default function removeUser(meetingId, userId) {
   };
 
   try {
+    setloggedOutStatus(userId, meetingId, true);
     VideoStreams.remove({ meetingId, userId });
     const sessionUserId = `${meetingId}-${userId}`;
 
diff --git a/bigbluebutton-html5/imports/ui/components/chat/time-window-list/time-window-chat-item/container.jsx b/bigbluebutton-html5/imports/ui/components/chat/time-window-list/time-window-chat-item/container.jsx
index d22afc033160b971d784c63311cb1ab99a93e556..54496761446b59c432c41bda7be375c1d7abdcaf 100644
--- a/bigbluebutton-html5/imports/ui/components/chat/time-window-list/time-window-chat-item/container.jsx
+++ b/bigbluebutton-html5/imports/ui/components/chat/time-window-list/time-window-chat-item/container.jsx
@@ -50,7 +50,7 @@ export default function TimeWindowChatItemContainer(props) {
       ...{
         color: user?.color,
         isModerator: user?.role === ROLE_MODERATOR,
-        isOnline: !!user,
+        isOnline: !user?.loggedOut,
         avatar: user?.avatar,
         name: user?.name,
         read: message.read,
diff --git a/bigbluebutton-html5/imports/ui/components/components-data/users-context/adapter.jsx b/bigbluebutton-html5/imports/ui/components/components-data/users-context/adapter.jsx
index 3d6d9ca29eace430bdc6b0232b2f71fb54fb66ba..f412c155f45f03df5bddd42beda67c7d86da98f7 100644
--- a/bigbluebutton-html5/imports/ui/components/components-data/users-context/adapter.jsx
+++ b/bigbluebutton-html5/imports/ui/components/components-data/users-context/adapter.jsx
@@ -1,5 +1,6 @@
 import { useContext, useEffect } from 'react';
 import Users from '/imports/api/users';
+import UsersPersistentData from '/imports/api/users-persistent-data';
 import { UsersContext, ACTIONS } from './context';
 import { ChatContext, ACTIONS as CHAT_ACTIONS } from '../chat-context/context';
 import ChatLogger from '/imports/ui/components/chat/chat-logger/ChatLogger';
@@ -8,8 +9,30 @@ const Adapter = () => {
   const usingUsersContext = useContext(UsersContext);
   const { dispatch } = usingUsersContext;
 
-  const usingChatContext = useContext(ChatContext);
-  const { dispatch: chatDispatch } = usingChatContext;
+  useEffect(()=> {
+    const usersPersistentDataCursor = UsersPersistentData.find({}, { sort: { timestamp: 1 } });
+    usersPersistentDataCursor.observe({
+      added: (obj) => {
+        ChatLogger.debug("usersAdapter::observe::added_persistent_user", obj);
+        dispatch({
+          type: ACTIONS.ADDED_USER_PERSISTENT_DATA,
+          value: {
+            user: obj,
+          },
+        });
+      },
+      changed: (obj) => {
+        ChatLogger.debug("usersAdapter::observe::changed_persistent_user", obj);
+        dispatch({
+          type: ACTIONS.CHANGED_USER_PERSISTENT_DATA,
+          value: {
+            user: obj,
+          },
+        });
+      },
+      removed: (obj) => {},
+    });
+  }, []);
 
   useEffect(() => {
     const usersCursor = Users.find({}, { sort: { timestamp: 1 } });
@@ -31,14 +54,6 @@ const Adapter = () => {
           },
         });
       },
-      removed: (obj) => {
-        dispatch({
-          type: ACTIONS.REMOVED,
-          value: {
-            user: obj,
-          },
-        });
-      },
     });
   }, []);
 
diff --git a/bigbluebutton-html5/imports/ui/components/components-data/users-context/context.jsx b/bigbluebutton-html5/imports/ui/components/components-data/users-context/context.jsx
index bf107b4038acdf70e11031dbd1eb2cad8bd4f5e3..18585a8b2a75a8f0fb46b10783c57581e794baf3 100644
--- a/bigbluebutton-html5/imports/ui/components/components-data/users-context/context.jsx
+++ b/bigbluebutton-html5/imports/ui/components/components-data/users-context/context.jsx
@@ -9,6 +9,8 @@ export const ACTIONS = {
   ADDED: 'added',
   CHANGED: 'changed',
   REMOVED: 'removed',
+  ADDED_USER_PERSISTENT_DATA: 'added_user_persistent_data',
+  CHANGED_USER_PERSISTENT_DATA: 'changed_user_persistent_data',
 };
 
 export const UsersContext = createContext();
@@ -47,6 +49,37 @@ const reducer = (state, action) => {
 
       return state;
     }
+
+    //USER PERSISTENT DATA
+    case ACTIONS.ADDED_USER_PERSISTENT_DATA: {
+      const { user } = action.value;
+      if (state[user.userId]) {
+        return state;
+      }
+
+      const newState = {
+        ...state,
+        [user.userId]: {
+          ...user,
+        },
+      };
+      return newState;
+    }
+    case ACTIONS.CHANGED_USER_PERSISTENT_DATA: {
+      const { user } = action.value;
+      const stateUser = state[user.userId];
+      if (stateUser) {
+        const newState = {
+          ...state,
+          [user.userId]: {
+            ...stateUser,
+            ...user,
+          },
+        };
+        return newState;
+      }
+      return state;
+    }
     default: {
       throw new Error(`Unexpected action: ${JSON.stringify(action)}`);
     }
diff --git a/bigbluebutton-html5/imports/ui/components/subscriptions/component.jsx b/bigbluebutton-html5/imports/ui/components/subscriptions/component.jsx
index 32b4698e35c0bedd2a33fa74682e37edebd95fb4..72c73e42e492b5a4e4a12beffc48b1aa36af094d 100755
--- a/bigbluebutton-html5/imports/ui/components/subscriptions/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/subscriptions/component.jsx
@@ -36,6 +36,8 @@ class Subscriptions extends Component {
   }
 }
 
+let usersPersistentDataHandler = null;
+
 export default withTracker(() => {
   const { credentials } = Auth;
   const { meetingId, requesterUserId } = credentials;
@@ -105,6 +107,9 @@ export default withTracker(() => {
     const chatIds = chats.map(chat => chat.chatId);
     groupChatMessageHandler = Meteor.subscribe('group-chat-msg', chatIds, subscriptionErrorHandler);
   }
+  if (ready && !usersPersistentDataHandler) {
+    usersPersistentDataHandler = Meteor.subscribe('users-persistent-data');
+  }
 
   return {
     subscriptionsReady: ready,
diff --git a/bigbluebutton-html5/server/main.js b/bigbluebutton-html5/server/main.js
index f80a2ed45c29ca366ea60ccf24fca8668f194d54..3ff24d74a20fa2605ef534adde9bffb0ed0d65c1 100755
--- a/bigbluebutton-html5/server/main.js
+++ b/bigbluebutton-html5/server/main.js
@@ -21,6 +21,7 @@ import '/imports/api/whiteboard-multi-user/server';
 import '/imports/api/video-streams/server';
 import '/imports/api/network-information/server';
 import '/imports/api/users-infos/server';
+import '/imports/api/users-persistent-data/server';
 import '/imports/api/connection-status/server';
 import '/imports/api/note/server';
 import '/imports/api/external-videos/server';