diff --git a/config/opensearch_dashboards.yml b/config/opensearch_dashboards.yml
index 26c11904fa9..69f1f5d3afc 100644
--- a/config/opensearch_dashboards.yml
+++ b/config/opensearch_dashboards.yml
@@ -40,7 +40,10 @@
 # This node attribute should assign all nodes of the same cluster an integer value that increments with each new cluster that is spun up
 # e.g. in opensearch.yml file you would set the value to a setting using node.attr.cluster_id: 
 # Should only be enabled if there is a corresponding node attribute created in your OpenSearch config that matches the value here
-#opensearch.optimizedHealthcheckId: "cluster_id"
+#opensearch.optimizedHealthcheck.id: "cluster_id"
+#opensearch.optimizedHealthcheck.filters: {
+#  attribute_key: "attribute_value",
+#}
 
 # If your OpenSearch is protected with basic authentication, these settings provide
 # the username and password that the OpenSearch Dashboards server uses to perform maintenance on the OpenSearch Dashboards
diff --git a/src/core/server/opensearch/opensearch_config.test.ts b/src/core/server/opensearch/opensearch_config.test.ts
index afe1c7d2875..2dfaecd76dd 100644
--- a/src/core/server/opensearch/opensearch_config.test.ts
+++ b/src/core/server/opensearch/opensearch_config.test.ts
@@ -80,7 +80,7 @@ test('set correct defaults', () => {
       ],
       "ignoreVersionMismatch": false,
       "logQueries": false,
-      "optimizedHealthcheckId": undefined,
+      "optimizedHealthcheck": undefined,
       "password": undefined,
       "pingTimeout": "PT30S",
       "requestHeadersWhitelist": Array [
@@ -488,11 +488,20 @@ describe('deprecations', () => {
     `);
   });
 
-  it('logs a warning if elasticsearch.optimizedHealthcheckId is set and opensearch.optimizedHealthcheckId is not', () => {
+  it('logs a warning if elasticsearch.optimizedHealthcheckId is set and opensearch.optimizedHealthcheck.id is not', () => {
     const { messages } = applyLegacyDeprecations({ optimizedHealthcheckId: '' });
     expect(messages).toMatchInlineSnapshot(`
       Array [
-        "\\"elasticsearch.optimizedHealthcheckId\\" is deprecated and has been replaced by \\"opensearch.optimizedHealthcheckId\\"",
+        "\\"elasticsearch.optimizedHealthcheckId\\" is deprecated and has been replaced by \\"opensearch.optimizedHealthcheck.id\\"",
+      ]
+    `);
+  });
+
+  it('logs a warning if opensearch.optimizedHealthcheckId is set and opensearch.optimizedHealthcheck.id is not', () => {
+    const { messages } = applyOpenSearchDeprecations({ optimizedHealthcheckId: '' });
+    expect(messages).toMatchInlineSnapshot(`
+      Array [
+        "\\"opensearch.optimizedHealthcheckId\\" is deprecated and has been replaced by \\"opensearch.optimizedHealthcheck.id\\"",
       ]
     `);
   });
diff --git a/src/core/server/opensearch/opensearch_config.ts b/src/core/server/opensearch/opensearch_config.ts
index 4bffca8b4b1..e5a0196eb04 100644
--- a/src/core/server/opensearch/opensearch_config.ts
+++ b/src/core/server/opensearch/opensearch_config.ts
@@ -84,7 +84,14 @@ export const configSchema = schema.object({
   requestTimeout: schema.duration({ defaultValue: '30s' }),
   pingTimeout: schema.duration({ defaultValue: schema.siblingRef('requestTimeout') }),
   logQueries: schema.boolean({ defaultValue: false }),
-  optimizedHealthcheckId: schema.maybe(schema.string()),
+  optimizedHealthcheck: schema.maybe(
+    schema.object({
+      id: schema.string(),
+      filters: schema.maybe(
+        schema.recordOf(schema.string(), schema.string(), { defaultValue: {} })
+      ),
+    })
+  ),
   ssl: schema.object(
     {
       verificationMode: schema.oneOf(
@@ -148,7 +155,8 @@ const deprecations: ConfigDeprecationProvider = ({ renameFromRoot }) => [
   renameFromRoot('elasticsearch.requestTimeout', 'opensearch.requestTimeout'),
   renameFromRoot('elasticsearch.pingTimeout', 'opensearch.pingTimeout'),
   renameFromRoot('elasticsearch.logQueries', 'opensearch.logQueries'),
-  renameFromRoot('elasticsearch.optimizedHealthcheckId', 'opensearch.optimizedHealthcheckId'),
+  renameFromRoot('elasticsearch.optimizedHealthcheckId', 'opensearch.optimizedHealthcheck.id'),
+  renameFromRoot('opensearch.optimizedHealthcheckId', 'opensearch.optimizedHealthcheck.id'),
   renameFromRoot('elasticsearch.ssl', 'opensearch.ssl'),
   renameFromRoot('elasticsearch.apiVersion', 'opensearch.apiVersion'),
   renameFromRoot('elasticsearch.healthCheck', 'opensearch.healthCheck'),
@@ -216,7 +224,7 @@ export class OpenSearchConfig {
    * Specifies whether Dashboards should only query the local OpenSearch node when
    * all nodes in the cluster have the same node attribute value
    */
-  public readonly optimizedHealthcheckId?: string;
+  public readonly optimizedHealthcheck?: OpenSearchConfigType['optimizedHealthcheck'];
 
   /**
    * Hosts that the client will connect to. If sniffing is enabled, this list will
@@ -297,7 +305,7 @@ export class OpenSearchConfig {
     this.ignoreVersionMismatch = rawConfig.ignoreVersionMismatch;
     this.apiVersion = rawConfig.apiVersion;
     this.logQueries = rawConfig.logQueries;
-    this.optimizedHealthcheckId = rawConfig.optimizedHealthcheckId;
+    this.optimizedHealthcheck = rawConfig.optimizedHealthcheck;
     this.hosts = Array.isArray(rawConfig.hosts) ? rawConfig.hosts : [rawConfig.hosts];
     this.requestHeadersWhitelist = Array.isArray(rawConfig.requestHeadersWhitelist)
       ? rawConfig.requestHeadersWhitelist
diff --git a/src/core/server/opensearch/opensearch_service.ts b/src/core/server/opensearch/opensearch_service.ts
index e853dbca6c5..5d9d2bcf85a 100644
--- a/src/core/server/opensearch/opensearch_service.ts
+++ b/src/core/server/opensearch/opensearch_service.ts
@@ -95,7 +95,7 @@ export class OpenSearchService
 
     const opensearchNodesCompatibility$ = pollOpenSearchNodesVersion({
       internalClient: this.client.asInternalUser,
-      optimizedHealthcheckId: config.optimizedHealthcheckId,
+      optimizedHealthcheck: config.optimizedHealthcheck,
       log: this.log,
       ignoreVersionMismatch: config.ignoreVersionMismatch,
       opensearchVersionCheckInterval: config.healthCheckDelay.asMilliseconds(),
diff --git a/src/core/server/opensearch/version_check/ensure_opensearch_version.test.ts b/src/core/server/opensearch/version_check/ensure_opensearch_version.test.ts
index dbbc0f2236e..99e24f19218 100644
--- a/src/core/server/opensearch/version_check/ensure_opensearch_version.test.ts
+++ b/src/core/server/opensearch/version_check/ensure_opensearch_version.test.ts
@@ -67,6 +67,35 @@ function createNodes(...versions: string[]): NodesInfo {
   return { nodes };
 }
 
+function createNodesWithAttribute(
+  targetId: string,
+  filterId: string,
+  targetAttributeValue: string,
+  filterAttributeValue: string,
+  ...versions: string[]
+): NodesInfo {
+  const nodes = {} as any;
+  versions
+    .map((version, i) => {
+      return {
+        version,
+        http: {
+          publish_address: 'http_address',
+        },
+        ip: 'ip',
+        attributes: {
+          cluster_id: i % 2 === 0 ? targetId : filterId,
+          custom_attribute: i % 2 === 0 ? targetAttributeValue : filterAttributeValue,
+        },
+      };
+    })
+    .forEach((node, i) => {
+      nodes[`node-${i}`] = node;
+    });
+
+  return { nodes };
+}
+
 describe('mapNodesVersionCompatibility', () => {
   function createNodesInfoWithoutHTTP(version: string): NodesInfo {
     return { nodes: { 'node-without-http': { version, ip: 'ip' } } } as any;
@@ -180,7 +209,7 @@ describe('pollOpenSearchNodesVersion', () => {
 
     pollOpenSearchNodesVersion({
       internalClient,
-      optimizedHealthcheckId: 'cluster_id',
+      optimizedHealthcheck: { id: 'cluster_id' },
       opensearchVersionCheckInterval: 1,
       ignoreVersionMismatch: false,
       opensearchDashboardsVersion: OPENSEARCH_DASHBOARDS_VERSION,
@@ -204,7 +233,104 @@ describe('pollOpenSearchNodesVersion', () => {
 
     pollOpenSearchNodesVersion({
       internalClient,
-      optimizedHealthcheckId: 'cluster_id',
+      optimizedHealthcheck: { id: 'cluster_id' },
+      opensearchVersionCheckInterval: 1,
+      ignoreVersionMismatch: false,
+      opensearchDashboardsVersion: OPENSEARCH_DASHBOARDS_VERSION,
+      log: mockLogger,
+    })
+      .pipe(take(1))
+      .subscribe({
+        next: (result) => {
+          expect(result).toEqual(
+            mapNodesVersionCompatibility(nodes, OPENSEARCH_DASHBOARDS_VERSION, false)
+          );
+        },
+        complete: done,
+        error: done,
+      });
+  });
+
+  it('returns compatibility results and isCompatible=true with filters', (done) => {
+    expect.assertions(2);
+    const target = {
+      id: '0',
+      attribute: 'foo',
+    };
+    const filter = {
+      id: '1',
+      attribute: 'bar',
+    };
+
+    // will filter out every odd index
+    const nodes = createNodesWithAttribute(
+      target.id,
+      filter.id,
+      target.attribute,
+      filter.attribute,
+      '5.1.0',
+      '6.2.0',
+      '5.1.0',
+      '5.1.1-Beta1'
+    );
+
+    // @ts-expect-error we need to return an incompatible type to use the testScheduler here
+    internalClient.cluster.state.mockReturnValueOnce({ body: nodes });
+
+    nodeInfosSuccessOnce(nodes);
+
+    pollOpenSearchNodesVersion({
+      internalClient,
+      optimizedHealthcheck: { id: target.id, filters: { custom_attribute: filter.attribute } },
+      opensearchVersionCheckInterval: 1,
+      ignoreVersionMismatch: false,
+      opensearchDashboardsVersion: OPENSEARCH_DASHBOARDS_VERSION,
+      log: mockLogger,
+    })
+      .pipe(take(1))
+      .subscribe({
+        next: (result) => {
+          expect(result).toEqual(
+            mapNodesVersionCompatibility(nodes, OPENSEARCH_DASHBOARDS_VERSION, false)
+          );
+          expect(result.isCompatible).toBe(true);
+        },
+        complete: done,
+        error: done,
+      });
+  });
+
+  it('returns compatibility results and isCompatible=false with filters', (done) => {
+    expect.assertions(2);
+    const target = {
+      id: '0',
+      attribute: 'foo',
+    };
+    const filter = {
+      id: '1',
+      attribute: 'bar',
+    };
+
+    // will filter out every odd index
+    const nodes = createNodesWithAttribute(
+      target.id,
+      filter.id,
+      target.attribute,
+      filter.attribute,
+      '5.1.0',
+      '5.1.0',
+      '6.2.0',
+      '5.1.1-Beta1'
+    );
+
+    // @ts-expect-error we need to return an incompatible type to use the testScheduler here
+    internalClient.cluster.state.mockReturnValueOnce({ body: nodes });
+
+    nodeInfosSuccessOnce(nodes);
+
+    pollOpenSearchNodesVersion({
+      internalClient,
+      optimizedHealthcheck: { id: target.id, filters: { custom_attribute: filter.attribute } },
       opensearchVersionCheckInterval: 1,
       ignoreVersionMismatch: false,
       opensearchDashboardsVersion: OPENSEARCH_DASHBOARDS_VERSION,
@@ -216,6 +342,7 @@ describe('pollOpenSearchNodesVersion', () => {
           expect(result).toEqual(
             mapNodesVersionCompatibility(nodes, OPENSEARCH_DASHBOARDS_VERSION, false)
           );
+          expect(result.isCompatible).toBe(false);
         },
         complete: done,
         error: done,
@@ -233,7 +360,7 @@ describe('pollOpenSearchNodesVersion', () => {
 
     pollOpenSearchNodesVersion({
       internalClient,
-      optimizedHealthcheckId: 'cluster_id',
+      optimizedHealthcheck: { id: 'cluster_id' },
       opensearchVersionCheckInterval: 1,
       ignoreVersionMismatch: false,
       opensearchDashboardsVersion: OPENSEARCH_DASHBOARDS_VERSION,
@@ -269,7 +396,7 @@ describe('pollOpenSearchNodesVersion', () => {
 
       const opensearchNodesCompatibility$ = pollOpenSearchNodesVersion({
         internalClient,
-        optimizedHealthcheckId: 'cluster_id',
+        optimizedHealthcheck: { id: 'cluster_id' },
         opensearchVersionCheckInterval: 100,
         ignoreVersionMismatch: false,
         opensearchDashboardsVersion: OPENSEARCH_DASHBOARDS_VERSION,
@@ -309,7 +436,7 @@ describe('pollOpenSearchNodesVersion', () => {
 
       const opensearchNodesCompatibility$ = pollOpenSearchNodesVersion({
         internalClient,
-        optimizedHealthcheckId: 'cluster_id',
+        optimizedHealthcheck: { id: 'cluster_id' },
         opensearchVersionCheckInterval: 10,
         ignoreVersionMismatch: false,
         opensearchDashboardsVersion: OPENSEARCH_DASHBOARDS_VERSION,
diff --git a/src/core/server/opensearch/version_check/ensure_opensearch_version.ts b/src/core/server/opensearch/version_check/ensure_opensearch_version.ts
index 3f1a88a42cb..04fb20a988e 100644
--- a/src/core/server/opensearch/version_check/ensure_opensearch_version.ts
+++ b/src/core/server/opensearch/version_check/ensure_opensearch_version.ts
@@ -38,6 +38,7 @@
 import { timer, of, from, Observable } from 'rxjs';
 import { map, distinctUntilChanged, catchError, exhaustMap, mergeMap } from 'rxjs/operators';
 import { get } from 'lodash';
+import { ApiResponse } from '@elastic/elasticsearch';
 import {
   opensearchVersionCompatibleWithOpenSearchDashboards,
   opensearchVersionEqualsOpenSearchDashboards,
@@ -47,38 +48,68 @@ import type { OpenSearchClient } from '../client';
 
 /**
  * Checks if all nodes in the cluster have the same cluster id node attribute
- * that is supplied through the healthcheckAttributeName param. This node attribute is configurable
- * in opensearch_dashboards.yml.
+ * that is supplied through the healthcheck param. This node attribute is configurable
+ * in opensearch_dashboards.yml. It can also filter attributes out by key-value pair.
  * If all nodes have the same cluster id then we do not fan out the healthcheck and use '_local' node
  * If there are multiple cluster ids then we use the default fan out behavior
  * If the supplied node attribute is missing then we return null and use default fan out behavior
  * @param {OpenSearchClient} internalClient
- * @param {string} healthcheckAttributeName
+ * @param {OptimizedHealthcheck} healthcheck
  * @returns {string|null} '_local' if all nodes have the same cluster_id, otherwise null
  */
 export const getNodeId = async (
   internalClient: OpenSearchClient,
-  healthcheckAttributeName: string
+  healthcheck: OptimizedHealthcheck
 ): Promise<string | null> => {
   try {
-    const state = await internalClient.cluster.state({
+    let path = `nodes.*.attributes.${healthcheck.id}`;
+    const filters = healthcheck.filters;
+    if (filters) {
+      Object.keys(filters).forEach((key) => {
+        path += `,nodes.*.attributes.${key}`;
+      });
+    }
+
+    const state = (await internalClient.cluster.state({
       metric: 'nodes',
-      filter_path: [`nodes.*.attributes.${healthcheckAttributeName}`],
-    });
+      filter_path: [path],
+    })) as ApiResponse;
     /* Aggregate different cluster_ids from the OpenSearch nodes
      * if all the nodes have the same cluster_id, retrieve nodes.info from _local node only
      * Using _cluster/state/nodes to retrieve the cluster_id of each node from master node which is considered to be a lightweight operation
      * else if the nodes have different cluster_ids then fan out the request to all nodes
      * else there are no nodes in the cluster
      */
-    const sharedClusterId =
-      state.body.nodes.length > 0
-        ? get(state.body.nodes[0], `attributes.${healthcheckAttributeName}`, null)
-        : null;
+    const nodes = state.body.nodes;
+    let nodeIds = Object.keys(nodes);
+    if (nodeIds.length === 0) {
+      return null;
+    }
+
+    /*
+     * If filters are set look for the key and value and filter out any node that matches
+     * the value for that attribute.
+     */
+    if (filters) {
+      nodeIds.forEach((id) => {
+        Object.keys(filters).forEach((key) => {
+          const attributeValue = get(nodes[id], `attributes.${key}`, null);
+          if (attributeValue === filters[key]) {
+            delete nodes[id];
+          }
+        });
+      });
+
+      nodeIds = Object.keys(nodes);
+      if (nodeIds.length === 0) {
+        return null;
+      }
+    }
+
+    const sharedClusterId = get(nodes[nodeIds[0]], `attributes.${healthcheck.id}`, null);
+
     return sharedClusterId === null ||
-      state.body.nodes.find(
-        (node: any) => sharedClusterId !== get(node, `attributes.${healthcheckAttributeName}`, null)
-      )
+      nodes.find((node: any) => sharedClusterId !== get(node, `attributes.${healthcheck.id}`, null))
       ? null
       : '_local';
   } catch (e) {
@@ -88,7 +119,7 @@ export const getNodeId = async (
 
 export interface PollOpenSearchNodesVersionOptions {
   internalClient: OpenSearchClient;
-  optimizedHealthcheckId?: string;
+  optimizedHealthcheck?: OptimizedHealthcheck;
   log: Logger;
   opensearchDashboardsVersion: string;
   ignoreVersionMismatch: boolean;
@@ -118,6 +149,13 @@ export interface NodesVersionCompatibility {
   opensearchDashboardsVersion: string;
 }
 
+export interface OptimizedHealthcheck {
+  id?: string;
+  filters?: {
+    [key: string]: string;
+  };
+}
+
 function getHumanizedNodeName(node: NodeInfo) {
   const publishAddress = node?.http?.publish_address + ' ' || '';
   return 'v' + node.version + ' @ ' + publishAddress + '(' + node.ip + ')';
@@ -201,7 +239,7 @@ function compareNodes(prev: NodesVersionCompatibility, curr: NodesVersionCompati
 
 export const pollOpenSearchNodesVersion = ({
   internalClient,
-  optimizedHealthcheckId,
+  optimizedHealthcheck,
   log,
   opensearchDashboardsVersion,
   ignoreVersionMismatch,
@@ -214,10 +252,10 @@ export const pollOpenSearchNodesVersion = ({
        * Originally, Dashboards queries OpenSearch cluster to get the version info of each node and check the version compatibility with each node.
        * The /nodes request could fail even one node in cluster fail to response
        * For better dashboards resilience, the behaviour is changed to only query the local node when all the nodes have the same cluster_id
-       * Using _cluster/state/nodes to retrieve the cluster_id of each node from the master node
+       * Using _cluster/state/nodes to retrieve the cluster_id of each node from the cluster manager node
        */
-      if (optimizedHealthcheckId) {
-        return from(getNodeId(internalClient, optimizedHealthcheckId)).pipe(
+      if (optimizedHealthcheck) {
+        return from(getNodeId(internalClient, optimizedHealthcheck)).pipe(
           mergeMap((nodeId: any) =>
             from(
               internalClient.nodes.info<NodesInfo>({