diff --git a/src/components/views/messages/MessageActionBar.tsx b/src/components/views/messages/MessageActionBar.tsx
index eebcb96b1e23f37f66b2ed8ce1353f6abf9b1b29..9130183e84e7bbbb243b9f7808e4f60881c8be36 100644
--- a/src/components/views/messages/MessageActionBar.tsx
+++ b/src/components/views/messages/MessageActionBar.tsx
@@ -24,6 +24,9 @@ import {
     MsgType,
     RelationType,
     M_BEACON_INFO,
+    EventTimeline,
+    RoomStateEvent,
+    EventType,
 } from "matrix-js-sdk/src/matrix";
 import classNames from "classnames";
 import { Icon as PinIcon } from "@vector-im/compound-design-tokens/icons/pin.svg";
@@ -278,12 +281,20 @@ export default class MessageActionBar extends React.PureComponent<IMessageAction
             this.props.mxEvent.once(MatrixEventEvent.Decrypted, this.onDecrypted);
         }
         this.props.mxEvent.on(MatrixEventEvent.BeforeRedaction, this.onBeforeRedaction);
+        this.context.room
+            ?.getLiveTimeline()
+            .getState(EventTimeline.FORWARDS)
+            ?.on(RoomStateEvent.Events, this.onRoomEvent);
     }
 
     public componentWillUnmount(): void {
         this.props.mxEvent.off(MatrixEventEvent.Status, this.onSent);
         this.props.mxEvent.off(MatrixEventEvent.Decrypted, this.onDecrypted);
         this.props.mxEvent.off(MatrixEventEvent.BeforeRedaction, this.onBeforeRedaction);
+        this.context.room
+            ?.getLiveTimeline()
+            .getState(EventTimeline.FORWARDS)
+            ?.off(RoomStateEvent.Events, this.onRoomEvent);
     }
 
     private onDecrypted = (): void => {
@@ -297,6 +308,12 @@ export default class MessageActionBar extends React.PureComponent<IMessageAction
         this.forceUpdate();
     };
 
+    private onRoomEvent = (event?: MatrixEvent): void => {
+        // If the event is pinned or unpinned, rerender the component.
+        if (!event || event.getType() !== EventType.RoomPinnedEvents) return;
+        this.forceUpdate();
+    };
+
     private onSent = (): void => {
         // When an event is sent and echoed the possible actions change.
         this.forceUpdate();
diff --git a/src/utils/EventUtils.ts b/src/utils/EventUtils.ts
index 373bcf49a7b20bb97d6b6fcb0435a9fce47a762d..dc5c89379b875721cd96a4397614ab004f083638 100644
--- a/src/utils/EventUtils.ts
+++ b/src/utils/EventUtils.ts
@@ -286,10 +286,6 @@ export function hasThreadSummary(event: MatrixEvent): boolean {
     return event.isThreadRoot && !!event.getThread()?.length && !!event.getThread()!.replyToEvent;
 }
 
-export function canPinEvent(event: MatrixEvent): boolean {
-    return !M_BEACON_INFO.matches(event.getType());
-}
-
 export const highlightEvent = (roomId: string, eventId: string): void => {
     defaultDispatcher.dispatch<ViewRoomPayload>({
         action: Action.ViewRoom,
diff --git a/src/utils/PinningUtils.ts b/src/utils/PinningUtils.ts
index 0d3323d50bec651e66337d142b30ecd60f815375..22db64a6f17bd2480e25adb4b166c3aa002767d9 100644
--- a/src/utils/PinningUtils.ts
+++ b/src/utils/PinningUtils.ts
@@ -16,7 +16,7 @@ limitations under the License.
 
 import { MatrixEvent, EventType, M_POLL_START, MatrixClient, EventTimeline } from "matrix-js-sdk/src/matrix";
 
-import { canPinEvent, isContentActionable } from "./EventUtils";
+import { isContentActionable } from "./EventUtils";
 import SettingsStore from "../settings/SettingsStore";
 import { ReadPinsEventId } from "../components/views/right_panel/types";
 
@@ -31,7 +31,8 @@ export default class PinningUtils {
     ];
 
     /**
-     * Determines if the given event may be pinned.
+     * Determines if the given event can be pinned.
+     * This is a simple check to see if the event is of a type that can be pinned.
      * @param {MatrixEvent} event The event to check.
      * @return {boolean} True if the event may be pinned, false otherwise.
      */
@@ -62,7 +63,8 @@ export default class PinningUtils {
     }
 
     /**
-     * Determines if the given event may be pinned or unpinned.
+     * Determines if the given event may be pinned or unpinned by the current user.
+     * This checks if the user has the necessary permissions to pin or unpin the event, and if the event is pinnable.
      * @param matrixClient
      * @param mxEvent
      */
@@ -77,7 +79,7 @@ export default class PinningUtils {
             room
                 .getLiveTimeline()
                 .getState(EventTimeline.FORWARDS)
-                ?.mayClientSendStateEvent(EventType.RoomPinnedEvents, matrixClient) && canPinEvent(mxEvent),
+                ?.mayClientSendStateEvent(EventType.RoomPinnedEvents, matrixClient) && PinningUtils.isPinnable(mxEvent),
         );
     }
 
@@ -101,16 +103,21 @@ export default class PinningUtils {
                 ?.getStateEvents(EventType.RoomPinnedEvents, "")
                 ?.getContent().pinned || [];
 
+        let roomAccountDataPromise: Promise<{} | void> = Promise.resolve();
         // If the event is already pinned, unpin it
         if (pinnedIds.includes(eventId)) {
             pinnedIds.splice(pinnedIds.indexOf(eventId), 1);
         } else {
             // Otherwise, pin it
             pinnedIds.push(eventId);
-            await matrixClient.setRoomAccountData(room.roomId, ReadPinsEventId, {
+            // We don't want to wait for the roomAccountDataPromise to resolve before sending the state event
+            roomAccountDataPromise = matrixClient.setRoomAccountData(room.roomId, ReadPinsEventId, {
                 event_ids: [...(room.getAccountData(ReadPinsEventId)?.getContent()?.event_ids || []), eventId],
             });
         }
-        await matrixClient.sendStateEvent(room.roomId, EventType.RoomPinnedEvents, { pinned: pinnedIds }, "");
+        await Promise.all([
+            matrixClient.sendStateEvent(room.roomId, EventType.RoomPinnedEvents, { pinned: pinnedIds }, ""),
+            roomAccountDataPromise,
+        ]);
     }
 }
diff --git a/test/components/views/messages/MessageActionBar-test.tsx b/test/components/views/messages/MessageActionBar-test.tsx
index ad184314a2587d8e5c23f4a60513049dffe492a5..9b5da31802fc7f7288bea084eee8252219138805 100644
--- a/test/components/views/messages/MessageActionBar-test.tsx
+++ b/test/components/views/messages/MessageActionBar-test.tsx
@@ -15,7 +15,7 @@ limitations under the License.
 */
 
 import React from "react";
-import { act, render, fireEvent } from "@testing-library/react";
+import { act, render, fireEvent, screen, waitFor } from "@testing-library/react";
 import {
     EventType,
     EventStatus,
@@ -26,6 +26,7 @@ import {
     FeatureSupport,
     Thread,
     EventTimeline,
+    RoomStateEvent,
 } from "matrix-js-sdk/src/matrix";
 
 import MessageActionBar from "../../../../src/components/views/messages/MessageActionBar";
@@ -41,6 +42,7 @@ import { IRoomState } from "../../../../src/components/structures/RoomView";
 import dispatcher from "../../../../src/dispatcher/dispatcher";
 import SettingsStore from "../../../../src/settings/SettingsStore";
 import { Action } from "../../../../src/dispatcher/actions";
+import PinningUtils from "../../../../src/utils/PinningUtils";
 
 jest.mock("../../../../src/dispatcher/dispatcher");
 
@@ -119,6 +121,7 @@ describe("<MessageActionBar />", () => {
         timelineRenderingType: TimelineRenderingType.Room,
         canSendMessages: true,
         canReact: true,
+        room,
     } as unknown as IRoomState;
     const getComponent = (props = {}, roomContext: Partial<IRoomState> = {}) =>
         render(
@@ -476,6 +479,7 @@ describe("<MessageActionBar />", () => {
         beforeEach(() => {
             // enable pin button
             jest.spyOn(SettingsStore, "getValue").mockReturnValue(true);
+            jest.spyOn(PinningUtils, "isPinned").mockReturnValue(false);
         });
 
         afterEach(() => {
@@ -499,5 +503,25 @@ describe("<MessageActionBar />", () => {
             const { queryByLabelText } = getComponent({ mxEvent: alicesMessageEvent });
             expect(queryByLabelText("Pin")).toBeTruthy();
         });
+
+        it("should listen to room pinned events", async () => {
+            getComponent({ mxEvent: alicesMessageEvent });
+            expect(screen.getByLabelText("Pin")).toBeInTheDocument();
+
+            // Event is considered pinned
+            jest.spyOn(PinningUtils, "isPinned").mockReturnValue(true);
+            // Emit that the room pinned events have changed
+            const roomState = room.getLiveTimeline().getState(EventTimeline.FORWARDS)!;
+            roomState.emit(
+                RoomStateEvent.Events,
+                {
+                    getType: () => EventType.RoomPinnedEvents,
+                } as MatrixEvent,
+                roomState,
+                null,
+            );
+
+            await waitFor(() => expect(screen.getByLabelText("Unpin")).toBeInTheDocument());
+        });
     });
 });
diff --git a/test/utils/PinningUtils-test.ts b/test/utils/PinningUtils-test.ts
index 07b26adb8a967ff9c7f123d16641d5d1ca77d618..47434c4fca3e881ab026cd6f90364c3b3cba4f3f 100644
--- a/test/utils/PinningUtils-test.ts
+++ b/test/utils/PinningUtils-test.ts
@@ -20,7 +20,7 @@ import { mocked } from "jest-mock";
 import { createTestClient } from "../test-utils";
 import PinningUtils from "../../src/utils/PinningUtils";
 import SettingsStore from "../../src/settings/SettingsStore";
-import { canPinEvent, isContentActionable } from "../../src/utils/EventUtils";
+import { isContentActionable } from "../../src/utils/EventUtils";
 import { ReadPinsEventId } from "../../src/components/views/right_panel/types";
 
 jest.mock("../../src/utils/EventUtils", () => {
@@ -35,7 +35,6 @@ describe("PinningUtils", () => {
     const userId = "@alice:example.org";
 
     const mockedIsContentActionable = mocked(isContentActionable);
-    const mockedCanPinEvent = mocked(canPinEvent);
 
     let matrixClient: MatrixClient;
     let room: Room;
@@ -63,7 +62,6 @@ describe("PinningUtils", () => {
         // Enable feature pinning
         jest.spyOn(SettingsStore, "getValue").mockReturnValue(true);
         mockedIsContentActionable.mockImplementation(() => true);
-        mockedCanPinEvent.mockImplementation(() => true);
 
         matrixClient = createTestClient();
         room = new Room(roomId, matrixClient, userId);
@@ -171,8 +169,7 @@ describe("PinningUtils", () => {
         });
 
         test("should return false if event is not pinnable", () => {
-            mockedCanPinEvent.mockReturnValue(false);
-            const event = makePinEvent();
+            const event = makePinEvent({ type: EventType.RoomCreate });
 
             expect(PinningUtils.canPinOrUnpin(matrixClient, event)).toBe(false);
         });