docs(P13e): reconcile docs drift — Administration Guide: Onboard + Upgrade + Comply (#37480)

* docs(P13e): reconcile drift for Administration Guide onboard/upgrade/comply pages

Ports content changes made in the legacy Sphinx docs repo since the P13
migration fork point (2026-05-14) into the corresponding MDX pages: SAML/SSO
Entra ID namespace-matching guidance, granular permissions updates, upgrade
notes for v11.7/v11.8, OSS component list, and minor typo/link fixes across
onboard, upgrade, and comply sections.

* docs(P13e): fix MDX compile failure from blank lines inside <pre><code> blocks

Blank lines inside JSX <pre><code> blocks are parsed as paragraph
boundaries by MDX, breaking the enclosing tag matching. Remove the
blank lines used for SQL readability while keeping each statement on
its own line.

* docs(P13e): fix insecure curl example and legacy absolute doc link

- electronic-discovery.mdx: use https for the authenticated curl
  example, matching the other curl examples in the same page.
- important-upgrade-notes.mdx: point the Deprecated Features reference
  at the local route instead of the legacy docs.mattermost.com URL.

---------

Co-authored-by: Hanzo Dev <[email protected]>
This commit is contained in:
Eva Sarafianou
2026-07-14 12:14:12 +03:00
committed by GitHub
co-authored by Hanzo Dev
parent 5fe06ac4d0
commit b07a9836ba
13 changed files with 279 additions and 11 deletions
@@ -55,7 +55,7 @@ x-version-id: 5.0.0.5.0.1.18c0fbd759664a85fe95132bb7fc04cf.true
Include the `token` value sent in the response as part of the Authorization header on your future API requests with the Bearer method, e.g.:
``` sh
curl -i -H 'Authorization: Bearer yi94pwci6ibjfc9phbikhqutbe http://yourmattermosturl/api/v4/users/me'
curl -i -H 'Authorization: Bearer yi94pwci6ibjfc9phbikhqutbe' https://yourmattermosturl/api/v4/users/me
```
Once you're authenticated into Mattermost, you can use the [Compliance API to create a new compliance report](https://api.mattermost.com/#tag/compliance%2Fpaths%2F~1compliance~1reports%2Fpost). The curl based example below demonstrates how to send a request that bases the authentication token and asks Mattermost to create a report that spans posts from Dec 31, 2017 - 8:15 PM to Dec 31, 2018 - 8:15 PM for a user with the email address [[email protected]](mailto:[email protected]):
@@ -366,6 +366,10 @@ The following tables list the comprehensive audit event types (`event_name` valu
<td>Restoring deleted channels</td>
</tr>
<tr>
<td><code>setChannelMembers</code></td>
<td>Bulk set (replace) channel memberships</td>
</tr>
<tr>
<td><code>updateChannel</code></td>
<td>Updating channel information</td>
</tr>
@@ -617,6 +617,12 @@ Permissions in Mattermost are a property of the server code base and are not cre
<td>Manage attribute-based access control rules for channels.</td>
<td></td>
</tr>
<tr>
<td>manage_team_access_rules</td>
<td>team</td>
<td>Manage attribute-based channel membership policies for a team from Team Settings.</td>
<td></td>
</tr>
</tbody>
</table>
@@ -1026,6 +1032,7 @@ The following built-in roles with default permissions are available:
- order_bookmark_private_channel
- manage_channel_banner
- manage_channel_access_rules
- manage_team_access_rules
*team_guest*
@@ -177,6 +177,25 @@ Example: As the default for the entire system, only allow users to edit their ow
3. In the **All Members**, **Channel Administrators**, and **Team Administrators** panels, in the **Manage Posts** section, check the box for **Edit Posts**.
4. From any panel, select the gear button to set the global time limit to `300` seconds.
#### Restrict who can edit post attachments
From Mattermost v11.8, system admins can use the **Edit Attachments** permission to control whether users can add or remove file attachments when editing posts.
The **Edit Attachments** permission is separate from **Edit Own Posts**. Users with permission to edit a post can still update the post text, but they can't add or remove file attachments unless **Edit Attachments** is also enabled.
By default, **Edit Attachments** is granted to users who have permission to edit posts.
To allow users to edit post text without changing attachments:
1. Go to **System Console \> User Management \> Permissions**.
2. Select **Edit Scheme**.
3. In the applicable role panel, go to **Manage Posts**.
4. Enable **Edit Own Posts**.
5. Disable **Edit Attachments**.
6. Select **Save**.
If a user sees **Post attachments cannot be edited** when editing a post, they don't have permission to add or remove attachments for that post.
### Integration management
From Mattermost v11.2, the System Console provides enhanced controls for managing integrations (webhooks, slash commands, OAuth apps), including separate permissions for managing your own integrations versus other users' integrations.
@@ -211,7 +211,7 @@ There are two ways to assign roles:
</tr>
<tr>
<td>Reporting</td>
<td><dl><dt><strong>Site Statistics</strong></dt><dd><ul><li>PERMISSION_SYSCONSOLE_READ_REPORTING_SITE_STATISTICS</li><li>PERMISSION_SYSCONSOLE_WRITE_REPORTING_SITE_STATISTICS</li></ul></dd><dt><strong>Team Statistics</strong></dt><dd><ul><li>PERMISSION_SYSCONSOLE_READ_REPORTING_TEAM_STATISTICS</li><li>PERMISSION_SYSCONSOLE_WRITE_REPORTING_TEAM_STATISTICS</li></ul></dd><dt><strong>Server Logs</strong></dt><dd><ul><li>PERMISSION_SYSCONSOLE_READ_REPORTING_SERVER_LOGS</li><li>PERMISSION_SYSCONSOLE_WRITE_REPORTING_SERVER_LOGS</li></ul></dd></dl></td>
<td><dl><dt><strong>System Statistics</strong></dt><dd><ul><li>PERMISSION_SYSCONSOLE_READ_REPORTING_SITE_STATISTICS</li><li>PERMISSION_SYSCONSOLE_WRITE_REPORTING_SITE_STATISTICS</li></ul></dd><dt><strong>Team Statistics</strong></dt><dd><ul><li>PERMISSION_SYSCONSOLE_READ_REPORTING_TEAM_STATISTICS</li><li>PERMISSION_SYSCONSOLE_WRITE_REPORTING_TEAM_STATISTICS</li></ul></dd><dt><strong>Server Logs</strong></dt><dd><ul><li>PERMISSION_SYSCONSOLE_READ_REPORTING_SERVER_LOGS</li><li>PERMISSION_SYSCONSOLE_WRITE_REPORTING_SERVER_LOGS</li></ul></dd></dl></td>
</tr>
<tr>
<td>User Management</td>
@@ -65,7 +65,7 @@ When Mattermost is configured to use OpenID Connect or OAuth 2.0 for user authen
### Note about Microsoft Active Directory Tenants
A Microsoft Active Directory (AD) tenant is a dedicated instance of Azure Active Directory (Azure AD) that you own and would have received when signing up for a Microsoft cloud service, such as Azure or Entra ID. Tenants are commonly used by organizations who want to store information about their users, such as passwords, user profile data, and permissions. See the Microsoft Entra ID \[https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-create-new-tenant\](https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-create-new-tenant\)\`\_ documentation to learn more about getting an Azure AD tenant.
A Microsoft Active Directory (AD) tenant is a dedicated instance of Azure Active Directory (Azure AD) that you own and would have received when signing up for a Microsoft cloud service, such as Azure or Entra ID. Tenants are commonly used by organizations who want to store information about their users, such as passwords, user profile data, and permissions. See the [Microsoft Entra ID](https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-create-new-tenant) documentation to learn more about getting an Azure AD tenant.
To allow your Azure AD users to log in to Mattermost using Entra ID SSO, you must register Mattermost in the Microsoft Azure AD tenant that contains the users' information. The registration can be done from the [Microsoft Azure portal](https://portal.azure.com). The steps to register the Mattermost account in the tenant should be similar to those provided above, and you can find more information about [integrating apps with Azure AD here](https://learn.microsoft.com/en-us/azure/active-directory/develop/quickstart-create-new-tenant).
@@ -42,7 +42,22 @@ This page provides guidance on configuring SAML with Microsoft Entra ID for Matt
9. Select **Edit** in the **Attributes & Claims** section then set the below attributes:
> 1. Set the the **Unique User Identifier (Name ID)** required claim **Name identifier format** and **Source attribute** values as required for your environment. Setting the **Source attribute** to an immutable value such as `user.objectid` is recommended.
> 2. Edit claim names and namespaces under **Additional claims** to match SAML attribute settings you wish to set in Mattermost. Configurable settings are Email, Username, Id, Guest, Admin, First Name, Last Name, Nickname, Position, and Preferred Language.
> 2. Edit claim names **and namespaces** under **Additional claims** to match SAML attribute settings you wish to set in Mattermost. Configurable settings are Email, Username, Id, Guest, Admin, First Name, Last Name, Nickname, Position, and Preferred Language.
<Important>
Mattermost matches each attribute by its **full claim name**, including the namespace, exactly as it appears in the SAML assertion. By default, Entra ID emits its built-in claims under the namespace `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/` — so the claim that appears in the **Claim name** column as `emailaddress` is actually sent in the assertion as `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress`.
This means the value you enter in each Mattermost attribute field (step 15 of **Configure SAML Sign-On for Mattermost**, below) must be the **fully-qualified** claim name. Entering only the short name (for example, `email` or `name`) will **not** match, and login will fail with an error such as `SAML login was unsuccessful because one of the attributes is incorrect... <attribute> attribute is missing`.
You have two options:
- **Clear the namespace** on each claim in Entra ID under **Additional claims** so the claim name becomes the short value (for example, `email`), then enter that same short value in Mattermost; **or**
- **Leave the default namespace** in Entra ID and enter the fully-qualified claim name in Mattermost (for example, `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress`).
Whichever option you choose, the value in Mattermost must match the assertion **character-for-character**. If a login fails, the safest way to confirm the exact claim names being sent is to capture and decode the SAML response from the browser (for example, with the [SAML-tracer](https://addons.mozilla.org/firefox/addon/saml-tracer/) browser extension) and read the `Name` attribute of each `<Attribute>` element.
</Important>
10. Select **Edit** in the **SAML Certificates** section. Select **Sign SAML response and assertion** for **Signing Option** and **SHA-256** for **Signing Algorithm** then select **Save**.
11. Select the **Certificate (Base64)** Download link in the **SAML Certificates** section. This is the **Identity Provider Public Certificate** to be uploaded to Mattermost.
@@ -74,7 +89,7 @@ The **Test single sign-on with Mattermost SAML** tool in Microsoft Entra ID does
</Note>
15. Set attribute settings to match attributes configured in step 9 of the **Set up an enterprise app for Mattermost SSO in Entra ID** section.
15. Set attribute settings to match attributes configured in step 9 of the **Set up an enterprise app for Mattermost SSO in Entra ID** section. Each value must match the **full claim name** sent in the assertion, including the namespace, exactly. See the **important** note under step 9 for details and a common failure mode.
16. Set the **Login Button Text** to suit your environment.
17. Select the **Save** button.
@@ -26,6 +26,19 @@ Existing accounts won't update until they log in to the server.
</Note>
## Why does login fail with "one of the attributes is incorrect" / "`<attribute>` attribute is missing"?
A login failure with the error `SAML login was unsuccessful because one of the attributes is incorrect. Please contact your System Administrator.` — accompanied in the server logs by a detail such as `email attribute is missing` or `name attribute is missing` — means the assertion from your Identity Provider (IdP) did not contain an attribute whose name **exactly** matches what you configured in the Mattermost SAML attribute settings.
Mattermost matches each attribute by its full `Name` (or `FriendlyName`) as it appears in the assertion, character-for-character. The named attribute in the error message is the value you entered in Mattermost that could not be found.
This most often happens because the IdP sends attributes under a namespace. For example, Microsoft Entra ID emits its built-in claims under `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/` by default, so an attribute that looks like `email` in the Entra ID admin UI is actually sent in the assertion as `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/email`. Entering only `email` in Mattermost will not match.
To resolve this:
- Capture and decode the SAML response (for example, with the [SAML-tracer](https://addons.mozilla.org/firefox/addon/saml-tracer/) browser extension) and read the `Name` attribute of each `<Attribute>` element in the `<AttributeStatement>`.
- Set each Mattermost attribute field to the **exact** `Name` value from the assertion — including any namespace prefix — or reconfigure the IdP to emit the claim under the short name you want to use in Mattermost.
## Can SAML via Microsoft ADFS be configured with Integrated Windows Authentication (IWA)?
Yes. IWA is supported on the browser, with support added to iOS and Android mobile apps in Q2/2019 (mobile apps v1.18 and later).
@@ -36,7 +36,7 @@ If your organization requires more structure and project management artifacts fo
**DO NOT manipulate the Mattermost database**
- In particular, DO NOT manually delete data from the database directly. Mattermost is designed as a continuous archive and cannot be supported after manual manipulation.
- If you need to permanently delete a team or user, use the [mmctl user delete](/administration-guide/manage/mmctl-command-line-tool#mmctl-user-delete) command or the [mmctl user deletall](/administration-guide/manage/mmctl-command-line-tool#mmctl-user-deleteall) command.
- If you need to permanently delete a team or user, use the [mmctl user delete](/administration-guide/manage/mmctl-command-line-tool#mmctl-user-delete) command or the [mmctl user deleteall](/administration-guide/manage/mmctl-command-line-tool#mmctl-user-deleteall) command.
## Common tasks
@@ -18,11 +18,195 @@ We recommend reviewing the [additional upgrade notes](#additional-upgrade-notes)
</colgroup>
<tbody>
<tr>
<td rowspan="2"><blockquote><p>If you're upgrading from a version earlier than...</p></blockquote><dl><dt>====================================================</dt><dd><p>v11.6</p></dd></dl></td>
<td colspan="2" rowspan="2"><blockquote><p>Then...</p></blockquote><dl><dt>==================================================================================================================================================================</dt><dd><p>Single-channel guests are no longer counted toward the primary licensed seat count and are permitted free up to a 1:1 ratio with licensed seats. A new stat card, license row, and admin banner provide visibility into single-channel guest usage and overage warnings.</p></dd></dl></td>
<td rowspan="8">v11.8</td>
<td colspan="2">The Custom Profile Attributes property group is renamed from <code>custom_profile_attributes</code> to <code>access_control</code>, and CPA fields and values are migrated from the legacy property model to the v2 model. The functionality of the CPA feature is unchanged. Plugin developers that use CPA will need to register against the new group name.</td>
<td></td>
</tr>
<tr>
<td colspan="2"><p>Added a new <code>Version</code> column to the <code>PropertyGroups</code> table to distinguish PSAv1 (legacy) groups from PSAv2 groups. Existing groups default to version 1, preserving current behavior for all legacy callers. <code>PropertyGroups</code> is a small configuration-like table, and the <code>ADD COLUMN ... DEFAULT 1 NOT NULL</code> is a metadata-only operation in PostgreSQL — no table rewrite occurs and the <code>AccessExclusiveLock</code> on <code>PropertyGroups</code> is held only for milliseconds. The migrations are fully backwards-compatible and no database downtime is expected for this upgrade. The SQL queries included are:</p><pre><code>-- Pre-upgrade schema changes (Mattermost 11.8).
ALTER TABLE PropertyGroups ADD COLUMN IF NOT EXISTS Version integer DEFAULT 1 NOT NULL;</code></pre></td>
<td></td>
</tr>
<tr>
<td colspan="2"><p>Raised the PostgreSQL planner statistics target for <code>posts.rootid</code> and <code>posts.channelid</code> from the default 100 to 5000, and refreshes planner statistics with <code>ANALYZE posts (rootid, channelid)</code>. The <code>ALTER COLUMN ... SET STATISTICS</code> statements are metadata-only operations that acquire only a <code>SHARE UPDATE EXCLUSIVE</code> lock — no table rewrite occurs and concurrent SELECT, INSERT, UPDATE, and DELETE on <code>posts</code> remain unblocked. The <code>ANALYZE</code> step may take several minutes on large <code>posts</code> tables (100M+ rows) due to the larger sample size, but does not block reads or writes. The migrations are fully backwards-compatible and no database downtime is expected for this upgrade. The SQL queries included are:</p><pre><code>ALTER TABLE posts ALTER COLUMN rootid SET STATISTICS 5000;
ALTER TABLE posts ALTER COLUMN channelid SET STATISTICS 5000;
ANALYZE posts (rootid, channelid);</code></pre></td>
<td></td>
</tr>
<tr>
<td colspan="2"><p>Extended the <code>channel_type</code> enum with two new values: <code>'BO'</code> and <code>'BP'</code>. The <code>ALTER TYPE ... ADD VALUE</code> statements acquire a brief <code>AccessExclusiveLock</code> on the <code>channel_type</code> type only — no table rewrite occurs and no row-level locking is applied to the <code>channels</code> table, making the operation near-instant. The migrations are fully backwards-compatible and no database downtime is expected for this upgrade. The SQL queries included are:</p><pre><code>ALTER TYPE channel_type ADD VALUE IF NOT EXISTS 'BO';
ALTER TYPE channel_type ADD VALUE IF NOT EXISTS 'BP';</code></pre></td>
<td></td>
</tr>
<tr>
<td colspan="2"><p>Introduced four schema migrations to the property and attribute system (<code>PropertyFields</code>, <code>PropertyGroups</code>, <code>AttributeView</code>) as part of the same release cycle. Migrations 000168 and 000169 add a nullable <code>LinkedFieldID varchar(26)</code> column to <code>PropertyFields</code> and a partial concurrent index over it, enabling fields to reference another field as a link. Migrations 000176 and 000177 promote the existing Custom Profile Attributes property group to a more general <code>access_control</code> group by updating permission columns on <code>PropertyFields</code> rows, renaming the <code>PropertyGroups</code> entry from <code>custom_profile_attributes</code> to <code>access_control</code>, and narrowing the <code>AttributeView</code> materialized view to user-scoped attributes only. <strong>Migrations 000176 and 000177 must ship together.</strong> None of the affected tables are in the large-table list — the property system tables are small. Note: during the rolling-upgrade window, old-ESR nodes hard-coding <code>'custom_profile_attributes'</code> as the group lookup key will experience transient failures on CPA profile read/write endpoints and the ABAC policy-management admin UI; end-user channel access and the membership sync worker are unaffected. The migrations are fully backwards-compatible and no database downtime is expected for this upgrade. The SQL queries included are:</p><pre><code>-- 000168: Add LinkedFieldID column
ALTER TABLE PropertyFields ADD COLUMN IF NOT EXISTS LinkedFieldID varchar(26);
-- 000169: Create partial index on LinkedFieldID
CREATE INDEX CONCURRENTLY idx_propertyfields_linkedfieldid ON PropertyFields(LinkedFieldID) WHERE LinkedFieldID IS NOT NULL AND DeleteAt = 0;
-- 000176: Migrate CPA to access_control
UPDATE PropertyFields SET ObjectType = 'user' WHERE GroupID = (SELECT Id FROM PropertyGroups WHERE Name = 'custom_profile_attributes');
UPDATE PropertyGroups SET Name = 'access_control', Version = 2 WHERE Name = 'custom_profile_attributes';
-- 000177: Refresh AttributeView with user-scoped filter
DROP MATERIALIZED VIEW AttributeView;
CREATE MATERIALIZED VIEW AttributeView ... WHERE pf.ObjectType = 'user';</code></pre></td>
<td></td>
</tr>
<tr>
<td colspan="2"><p>Mattermost v11.8 introduces schema changes to the <code>Recaps</code> table in the form of a new <code>ViewedAt</code> column and a new index on <code>(UserId, ViewedAt)</code>. The column is added as a metadata-only operation, and the index is created using <code>CONCURRENTLY</code>, meaning no table locks are acquired and existing operations on the table are not impacted. The migrations are fully backwards-compatible and no database downtime is expected for this upgrade. The SQL queries included are:</p><pre><code>-- 000172_add_recaps_viewed_at.up.sql
ALTER TABLE Recaps ADD COLUMN IF NOT EXISTS ViewedAt BIGINT NOT NULL DEFAULT 0;
-- 000172_add_recaps_viewed_at.down.sql
ALTER TABLE Recaps DROP COLUMN IF EXISTS ViewedAt;
-- 000173_create_recaps_user_id_viewed_at_index.up.sql
-- morph:nontransactional
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_recaps_user_id_viewed_at ON Recaps(UserId, ViewedAt);
-- 000173_create_recaps_user_id_viewed_at_index.down.sql
-- morph:nontransactional
DROP INDEX CONCURRENTLY IF EXISTS idx_recaps_user_id_viewed_at;</code></pre></td>
<td></td>
</tr>
<tr>
<td colspan="2"><p>Mattermost v11.8 introduces six schema changes supporting a new channel join request workflow and discoverable private channels. A <code>Discoverable</code> boolean column (<code>DEFAULT FALSE</code>) is added to the <code>Channels</code> table as a metadata-only operation that completes instantaneously on PostgreSQL 11+. A new <code>ChannelJoinRequests</code> table is created to manage access request workflows, tracking request status, denial reasons, and reviewer information. Four concurrent indexes are then added: a partial index on <code>Channels</code> for discoverable team channels (<code>idx_channels_discoverable_team</code>), a unique partial index on <code>ChannelJoinRequests</code> for pending requests (<code>idx_channeljoinrequests_pending_unique</code>), and two composite indexes optimizing queries by channel+status and user+status respectively. All index operations use <code>CONCURRENTLY</code> and must be run outside explicit transaction blocks. These migrations are PostgreSQL-only. The migrations are fully backwards-compatible and no database downtime is expected for this upgrade. The SQL queries included are:</p><pre><code>-- Migration 000178: Add Discoverable column
ALTER TABLE Channels ADD COLUMN IF NOT EXISTS Discoverable BOOLEAN NOT NULL DEFAULT FALSE;</code></pre><pre><code>-- Migration 000179: Partial index for discoverable channels
-- Run outside a transaction block.
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_channels_discoverable_team
ON Channels (TeamId)
WHERE Discoverable = TRUE AND Type = 'P' AND DeleteAt = 0;</code></pre><pre><code>-- Migration 000180: Create ChannelJoinRequests table
CREATE TABLE IF NOT EXISTS ChannelJoinRequests (
Id VARCHAR(26) PRIMARY KEY,
ChannelId VARCHAR(26) NOT NULL,
UserId VARCHAR(26) NOT NULL,
Message TEXT NOT NULL DEFAULT '',
Status VARCHAR(16) NOT NULL DEFAULT 'pending',
DenialReason TEXT NOT NULL DEFAULT '',
CreateAt BIGINT NOT NULL,
UpdateAt BIGINT NOT NULL,
ReviewedBy VARCHAR(26) NOT NULL DEFAULT '',
ReviewedAt BIGINT NOT NULL DEFAULT 0
);</code></pre><pre><code>-- Migration 000181: Unique index for pending requests
-- Run outside a transaction block.
CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS idx_channeljoinrequests_pending_unique
ON ChannelJoinRequests (ChannelId, UserId)
WHERE Status = 'pending';</code></pre><pre><code>-- Migration 000182: Index for channel+status queries
-- Run outside a transaction block.
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_channeljoinrequests_channel_status_createat
ON ChannelJoinRequests (ChannelId, Status, CreateAt DESC);</code></pre><pre><code>-- Migration 000183: Index for user+status queries
-- Run outside a transaction block.
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_channeljoinrequests_user_status_createat
ON ChannelJoinRequests (UserId, Status, CreateAt DESC);</code></pre></td>
<td></td>
</tr>
<tr>
<td colspan="2"><p>Mattermost v11.8 extends the <code>permission_level</code> PostgreSQL enum type to include an <code>admin</code> value alongside the existing <code>none</code>, <code>sysadmin</code>, and <code>member</code> values. This is a pure catalog change — <code>ALTER TYPE ADD VALUE</code> updates only the <code>pg_type</code> system catalog and does not touch the <code>PropertyFields</code> table or any other application table. No columns, indexes, or table data are modified by the up migration. The change enables a new admin-level permission tier in the property field access control model. The migrations are fully backwards-compatible and no database downtime is expected for this upgrade. The SQL queries included are:</p><pre><code>-- 000189_add_admin_to_permission_level.up.sql
ALTER TYPE permission_level ADD VALUE IF NOT EXISTS 'admin';</code></pre></td>
<td></td>
</tr>
<tr>
<td rowspan="6">v11.7</td>
<td colspan="2">FIPS builds require a minimum of 14 characters for passwords, atmos/camo proxy configuration, and shared channel secrets. Shorter passwords for existing users will no longer be valid and require a password reset. Non-FIPS builds are unaffected.</td>
<td></td>
</tr>
<tr>
<td colspan="2"><p>Added a new partial unique index (<code>idx_accesscontrolpolicies_name_type</code>) to the <code>AccessControlPolicies</code> table on (Name, Type) filtered to <code>WHERE Type = 'parent'</code>. Before creating the index, duplicate parent policy names are resolved by appending the policy ID to all but the oldest entry. This enforces uniqueness of parent policy names and prevents future duplicates from being created. The migration targets <code>AccessControlPolicies</code>, not posts or reactions. For deployments where <code>AttributeBasedAccessControl</code> was not enabled, the table will be empty and the migration completes in under a second. For deployments where the flag was enabled, the number of parent policies is expected to remain small, so timing is still negligible. The <code>CREATE UNIQUE INDEX</code> (non-concurrent) takes a brief <code>SHARE</code> lock on <code>AccessControlPolicies</code>, blocking concurrent <code>INSERT/UPDATE/DELETE</code> for the duration of the index build. The <code>UPDATE</code> (deduplication) takes a <code>ROW EXCLUSIVE</code> lock on the same table. The migrations are fully backwards-compatible and no database downtime is expected for this upgrade. The SQL queries included are:</p><pre><code>-- PostgreSQL only (MySQL not supported in v11+):
-- Deduplicate parent policy names before adding unique constraint.
-- The oldest policy (by CreateAt) keeps its original name; duplicates get ' (&lt;id&gt;)' appended.
UPDATE AccessControlPolicies AS p
SET Name = LEFT(p.Name, 128 - LENGTH(' (' || p.ID || ')')) || ' (' || p.ID || ')'
FROM (
SELECT ID, Name, ROW_NUMBER() OVER (PARTITION BY Name ORDER BY CreateAt ASC) AS rn
FROM AccessControlPolicies
WHERE Type = 'parent'
) AS dupes
WHERE p.ID = dupes.ID
AND dupes.rn > 1;
CREATE UNIQUE INDEX IF NOT EXISTS idx_accesscontrolpolicies_name_type
ON AccessControlPolicies (Name, Type)
WHERE Type = 'parent';</code></pre></td>
<td></td>
</tr>
<tr>
<td colspan="2"><p>The <code>PropertyFields</code> table is modified. Two new nullable columns, <code>CreatedBy</code> and <code>UpdatedBy</code>, are added to track which user created and last modified each field. A new <code>ObjectType</code> column is added with a <code>NOT NULL</code> constraint and an empty string default, to discriminate between legacy and typed property fields. A new <code>Protected</code> boolean column is added with a default of <code>FALSE</code>, along with three new columns (<code>PermissionField</code>, <code>PermissionValues</code>, <code>PermissionOptions</code>) using a new <code>permission_level</code> enum type with values none, sysadmin, and member. The existing unique index <code>idx_propertyfields_unique</code> on (GroupID, TargetID, Name) is dropped and replaced by two new partial unique indexes: <code>idx_propertyfields_unique_legacy</code> which covers legacy rows where <code>ObjectType = ''</code> and <code>idx_propertyfields_unique_typed</code> which covers typed rows where <code>ObjectType != ''</code>, indexing (<code>ObjectType</code>, <code>GroupID</code>, <code>TargetType</code>, <code>TargetID</code>, <code>Name</code>).</p><p>The <code>PropertyValues</code> table is modified. Two new nullable columns, <code>CreatedBy</code> and <code>UpdatedBy</code>, are added, matching the same tracking columns on <code>PropertyFields</code>.</p><p>A new <code>Views</code> table is created. A new index <code>idx_views_channel_id_delete_at</code> on (<code>ChannelId</code>, <code>DeleteAt</code>) is created for this table.</p><p>Migrations 160, 161, and 165 use <code>ALTER TABLE ADD COLUMN</code>, which briefly acquires a lock, but this is instant (metadata-only) on PostgreSQL 11+. All other migrations, including index creation and deletion, use CONCURRENTLY and are lock-free. These eight migrations are safe for zero-downtime deployment. They only affect low-row-count tables (<code>PropertyFields</code>, <code>PropertyValues</code>) and create a new empty table (<code>Views</code>), with no full-table data modifications, no column type changes, and minimal I/O from concurrent index operations. The migrations are fully backwards-compatible and no database downtime is expected for this upgrade. The SQL queries included are:</p><pre><code>--- 160
ALTER TABLE PropertyFields
ADD COLUMN IF NOT EXISTS CreatedBy varchar(26),
ADD COLUMN IF NOT EXISTS UpdatedBy varchar(26);
ALTER TABLE PropertyValues
ADD COLUMN IF NOT EXISTS CreatedBy varchar(26),
ADD COLUMN IF NOT EXISTS UpdatedBy varchar(26);
--- 161
ALTER TABLE PropertyFields ADD COLUMN IF NOT EXISTS ObjectType varchar(255) NOT NULL DEFAULT '';
--- 162
DROP INDEX CONCURRENTLY IF EXISTS idx_propertyfields_unique;
--- 163
CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS idx_propertyfields_unique_legacy
ON PropertyFields (GroupID, TargetID, Name)
WHERE DeleteAt = 0 AND ObjectType = '';
--- 164
CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS idx_propertyfields_unique_typed
ON PropertyFields (ObjectType, GroupID, TargetType, TargetID, Name)
WHERE DeleteAt = 0 AND ObjectType != '';
--- 165
DO $$
BEGIN
IF NOT EXISTS (SELECT * FROM pg_type typ
INNER JOIN pg_namespace nsp ON nsp.oid = typ.typnamespace
WHERE nsp.nspname = current_schema()
AND typ.typname = 'permission_level') THEN
CREATE TYPE permission_level AS ENUM ('none', 'sysadmin', 'member');
END IF;
END;
$$
LANGUAGE plpgsql;
ALTER TABLE PropertyFields
ADD COLUMN IF NOT EXISTS Protected BOOLEAN NOT NULL DEFAULT FALSE,
ADD COLUMN IF NOT EXISTS PermissionField permission_level,
ADD COLUMN IF NOT EXISTS PermissionValues permission_level,
ADD COLUMN IF NOT EXISTS PermissionOptions permission_level;
--- 166
CREATE TABLE IF NOT EXISTS Views (
Id VARCHAR(26) PRIMARY KEY,
ChannelId VARCHAR(26) NOT NULL,
Type VARCHAR(32) NOT NULL,
CreatorId VARCHAR(26) NOT NULL,
Title VARCHAR(256) NOT NULL,
Description TEXT,
SortOrder INTEGER NOT NULL DEFAULT 0,
Props jsonb,
CreateAt BIGINT NOT NULL,
UpdateAt BIGINT NOT NULL,
DeleteAt BIGINT NOT NULL DEFAULT 0
);
--- 167
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_views_channel_id_delete_at ON Views(ChannelId, DeleteAt);
--- 171
DROP INDEX CONCURRENTLY IF EXISTS idx_propertyfields_protected;</code></pre></td>
<td></td>
</tr>
<tr>
<td colspan="2">The <code>role_updated</code> WebSocket events are scoped to the affected team/channel instead of broadcasting globally, improving performance and reducing unnecessary network traffic. No manual action is required from administrators as the migration runs automatically during the upgrade. No downtime is expected, and no special planning is needed for the upgrade as the migration can run during normal operations. All installations are affected by this change, but the impact is minimal since the <code>roles</code> table is small with well under 10k rows even on large installations. The upgrade includes automatic database migrations to add a <code>schemeid</code> column to the <code>roles</code> table for efficient role-scheme lookups. The migrations use PostgreSQL's non-blocking techniques: first adding the column with a brief ACCESS EXCLUSIVE lock (catalog-only operation), then backfilling existing data with a ROW EXCLUSIVE lock, and finally creating an index concurrently with a SHARE UPDATE EXCLUSIVE lock that doesn't block other operations. The <code>roles</code> table size is bounded and unaffected by posts, reactions, or other high-volume data. The migrations are fully backwards-compatible.</td>
<td></td>
</tr>
<tr>
<td colspan="2">v11.7 includes Agents plugin v2. Please see <a href="https://github.com/mattermost/mattermost-plugin-agents/blob/master/docs/upgrading_to_2.0.md">this guide</a> on how to upgrade the Mattermost Agents plugin from a v1.x release to v2.0.0. It covers the supported version path, the migrations that run automatically on first start of v2.0.0, the breaking changes and default-behavior flips that admins should know about before the upgrade window, and the verification steps to confirm the upgrade succeeded.</td>
<td></td>
</tr>
<tr>
<td colspan="2"><p>v11.7.6 migration removes orphaned rows from the <code>threadmemberships</code> table — specifically, rows where the associated user is no longer a member of the channel that the thread belongs to. The cleanup is performed via a filtered <code>DELETE</code> using a three-way join across <code>threadmemberships</code>, <code>threads</code>, and <code>channelmembers</code>. No schema objects (tables, columns, or indexes) are added or removed; only data rows are affected. Note for large instances: this migration issues a single unbatched delete that scans the entirety of <code>threadmemberships</code> with a join against <code>threads</code> and <code>channelmembers</code>. On databases with tens of millions of rows or significant historical channel-membership churn, this query may run for an extended period, block autovacuum on <code>threadmemberships</code>, increase WAL pressure, and contribute to replication lag. Administrators of large deployments should test execution time on a representative dataset before upgrading and consider scheduling the upgrade during a low-traffic window. The down migration contains no rollback SQL because the deleted rows cannot be recovered; this migration is irreversible. The migrations are fully backwards-compatible and no database downtime is expected for this upgrade. The SQL queries included are:</p><pre><code>-- Drop ThreadMembership rows whose user is no longer a member of the thread's channel.
DELETE FROM threadmemberships WHERE (postid, userid) IN (
SELECT
threadmemberships.postid,
threadmemberships.userid
FROM
threadmemberships
JOIN threads ON threads.postid = threadmemberships.postid
LEFT JOIN channelmembers ON channelmembers.userid = threadmemberships.userid
AND threads.channelid = channelmembers.channelid
WHERE
channelmembers.channelid IS NULL
);</code></pre></td>
<td></td>
</tr>
<tr>
<td>v11.6</td>
<td colspan="2">Single-channel guests are no longer counted toward the primary licensed seat count and are permitted free up to a 1:1 ratio with licensed seats. A new stat card, license row, and admin banner provide visibility into single-channel guest usage and overage warnings.</td>
<td></td>
</tr>
<tr>
@@ -177,7 +361,11 @@ We recommend reviewing the [additional upgrade notes](#additional-upgrade-notes)
<td></td>
</tr>
<tr>
<td rowspan="2">v10.11</td>
<td rowspan="4">v10.11</td>
<td colspan="2">Customers should not upgrade from <code>&gt;=10.11.17</code> to <code>&lt;=11.7.2</code> due to a bug that causes an issue with database migration numbers. The bug is fixed in v11.7.3.</td>
<td></td>
</tr>
<tr>
<td colspan="2">Starting in v10.11.11, photoshop Document (PSD) files are now no longer inline previewed, they are treated as regular file attachments.</td>
<td></td>
</tr>
@@ -186,6 +374,22 @@ We recommend reviewing the [additional upgrade notes](#additional-upgrade-notes)
<td></td>
</tr>
<tr>
<td colspan="2"><p>v10.11.21 migration removes orphaned rows from the <code>threadmemberships</code> table — specifically, rows where the associated user is no longer a member of the channel that the thread belongs to. The cleanup is performed via a filtered <code>DELETE</code> using a three-way join across <code>threadmemberships</code>, <code>threads</code>, and <code>channelmembers</code>. No schema objects (tables, columns, or indexes) are added or removed; only data rows are affected. Note for large instances: this migration issues a single unbatched delete that scans the entirety of <code>threadmemberships</code> with a join against <code>threads</code> and <code>channelmembers</code>. On databases with tens of millions of rows or significant historical channel-membership churn, this query may run for an extended period, block autovacuum on <code>threadmemberships</code>, increase WAL pressure, and contribute to replication lag. Administrators of large deployments should test execution time on a representative dataset before upgrading and consider scheduling the upgrade during a low-traffic window. The down migration contains no rollback SQL because the deleted rows cannot be recovered; this migration is irreversible. The migrations are fully backwards-compatible and no database downtime is expected for this upgrade. The SQL queries included are:</p><pre><code>-- Drop ThreadMembership rows whose user is no longer a member of the thread's channel.
DELETE FROM threadmemberships WHERE (postid, userid) IN (
SELECT
threadmemberships.postid,
threadmemberships.userid
FROM
threadmemberships
JOIN threads ON threads.postid = threadmemberships.postid
LEFT JOIN channelmembers ON channelmembers.userid = threadmemberships.userid
AND threads.channelid = channelmembers.channelid
WHERE
channelmembers.channelid IS NULL
);</code></pre></td>
<td></td>
</tr>
<tr>
<td rowspan="4">v10.10</td>
<td colspan="2"><p>Added a new column <code>DefaultCategoryName</code> to the <code>Channels</code> table. This is nullable and stores a category name to be added/created when new users join a channel. This is only used if the <code>ExperimentalChannelCategorySetting</code> is enabled. The migrations are fully backwards-compatible and no table locks or existing operations on the table are impacted by this upgrade. Zero downtime is expected when upgrading to this release. The SQL queries included are:</p><p>PostgreSQL: <a href="https://github.com/mattermost/mattermost/blob/release-10.10/server/channels/db/migrations/postgres/000138_add_default_category_name_to_channel.down.sql">https://github.com/mattermost/mattermost/blob/release-10.10/server/channels/db/migrations/postgres/000138_add_default_category_name_to_channel.down.sql</a> and <a href="https://github.com/mattermost/mattermost/blob/release-10.10/server/channels/db/migrations/postgres/000138_add_default_category_name_to_channel.up.sql">https://github.com/mattermost/mattermost/blob/release-10.10/server/channels/db/migrations/postgres/000138_add_default_category_name_to_channel.up.sql</a></p><p>MySQL: <a href="https://github.com/mattermost/mattermost/blob/release-10.10/server/channels/db/migrations/mysql/000138_add_default_category_name_to_channel.down.sql">https://github.com/mattermost/mattermost/blob/release-10.10/server/channels/db/migrations/mysql/000138_add_default_category_name_to_channel.down.sql</a> and <a href="https://github.com/mattermost/mattermost/blob/release-10.10/server/channels/db/migrations/mysql/000138_add_default_category_name_to_channel.up.sql">https://github.com/mattermost/mattermost/blob/release-10.10/server/channels/db/migrations/mysql/000138_add_default_category_name_to_channel.up.sql</a></p></td>
<td></td>
@@ -1162,6 +1366,7 @@ We recommend reviewing the [additional upgrade notes](#additional-upgrade-notes)
<Note>
- See the [Deprecated Features](/product-overview/deprecated-features) document for upcoming deprecations in the v12.0 (October 2026) release.
- Upgrading the Microsoft Teams Calling plugin to v2.0.0 requires users to reconnect their accounts.
- Mattermost plugins built with Go versions 1.22.0 and 1.22.1 do not work. Plugin developers should use Go 1.22.2 or newer instead.
- Keybase has stopped serving Mattermost's Ubuntu repository signing key. If you were using it, update your installation scripts to retrieve the key as mentioned in our [Linux deployment documentation](/deployment-guide/server/deploy-linux).
@@ -7,6 +7,7 @@ The following open source components are used to provide the full benefits of Ma
## Desktop
- Mattermost Desktop v6.2.0 - [View Open Source Components](https://github.com/mattermost/desktop/blob/release-6.2/NOTICE.txt).
- Mattermost Desktop v6.1.0 - [View Open Source Components](https://github.com/mattermost/desktop/blob/release-6.1/NOTICE.txt).
- Mattermost Desktop v6.0.0 - [View Open Source Components](https://github.com/mattermost/desktop/blob/release-6.0/NOTICE.txt).
- Mattermost Desktop v5.13.0 - [View Open Source Components](https://github.com/mattermost/desktop/blob/release-5.13/NOTICE.txt).
@@ -35,6 +36,8 @@ The following open source components are used to provide the full benefits of Ma
## Mobile
- Mattermost Mobile v2.41.0 - [View Open Source Components](https://github.com/mattermost/mattermost-mobile/blob/release-2.41/NOTICE.txt).
- Mattermost Mobile v2.40.0 - [View Open Source Components](https://github.com/mattermost/mattermost-mobile/blob/release-2.40/NOTICE.txt).
- Mattermost Mobile v2.39.0 - [View Open Source Components](https://github.com/mattermost/mattermost-mobile/blob/release-2.39/NOTICE.txt).
- Mattermost Mobile v2.38.0 - [View Open Source Components](https://github.com/mattermost/mattermost-mobile/blob/release-2.38/NOTICE.txt).
- Mattermost Mobile v2.37.0 - [View Open Source Components](https://github.com/mattermost/mattermost-mobile/blob/release-2.37/NOTICE.txt).
@@ -134,6 +137,8 @@ The following open source components are used to provide the full benefits of Ma
## Server
- Mattermost Enterprise Edition v11.8.0 - [View Open Source Components](https://github.com/mattermost/mattermost-server/blob/release-11.8/NOTICE.txt).
- Mattermost Enterprise Edition v11.7.0 - [View Open Source Components](https://github.com/mattermost/mattermost-server/blob/release-11.7/NOTICE.txt).
- Mattermost Enterprise Edition v11.6.0 - [View Open Source Components](https://github.com/mattermost/mattermost-server/blob/release-11.6/NOTICE.txt).
- Mattermost Enterprise Edition v11.5.0 - [View Open Source Components](https://github.com/mattermost/mattermost-server/blob/release-11.5/NOTICE.txt).
- Mattermost Enterprise Edition v11.4.0 - [View Open Source Components](https://github.com/mattermost/mattermost-server/blob/release-11.4/NOTICE.txt).
@@ -53,7 +53,7 @@ We strongly recommend that you:
<Important>
Support for Mattermost Server v10.5 [Extended Support Release](/product-overview/mattermost-server-releases) has come to the end of its life cycle on November 15, 2025. Upgrading to Mattermost Server v10.11 Extended Support Release or later is required. Upgrading from the previous Extended Support Release to the latest Extended Support Release is supported. Review the [important upgrade notes](/administration-guide/upgrade/important-upgrade-notes) for all intermediate versions in between to ensure you’re aware of the possible migrations that could affect your upgrade.
Support for Mattermost Server v10.11 [Extended Support Release](/product-overview/mattermost-server-releases) is coming to the end of its life cycle on August 15, 2026. Upgrading to Mattermost Server v11.7 Extended Support Release or later is recommended. Upgrading from the previous Extended Support Release to the latest Extended Support Release is supported. Review the [important upgrade notes](/administration-guide/upgrade/important-upgrade-notes) for all intermediate versions in between to ensure you’re aware of the possible migrations that could affect your upgrade.
</Important>
@@ -135,7 +135,7 @@ When running PostgreSQL in Docker, `pg_dump`/`pg_restore` is the recommended upg
## After the upgrade
After upgrading PostgreSQL, run `ANALYZE VERBOSE` on the Mattermost database. This re-populates the `pg_statistics` table used by PostgreSQL to generate optimal query plans. Skipping this step can result in degraded database performance.
After upgrading PostgreSQL, run `ANALYZE VERBOSE` on the Mattermost database. This re-populates the `pg_statistic` table used by PostgreSQL to generate optimal query plans. Skipping this step can result in degraded database performance.
``` sh
sudo -u postgres psql -d mattermost -c "ANALYZE VERBOSE;"