diff --git a/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/ml_experiments_show.vue b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/ml_experiments_show.vue
index afd48df93e4a2959e6b57b6e3983d953ffee682e..f492c3ec3585e2693cb5f9bfcd1c784b0f3301a0 100644
--- a/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/ml_experiments_show.vue
+++ b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/ml_experiments_show.vue
@@ -1,4 +1,5 @@
 <script>
+import { isEmpty } from 'lodash';
 import { GlTableLite, GlLink, GlEmptyState, GlButton } from '@gitlab/ui';
 import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
 import RegistrySearch from '~/vue_shared/components/registry/registry_search.vue';
@@ -129,6 +130,9 @@ export default {
     hasItems() {
       return this.candidates.length > 0;
     },
+    hasMetadata() {
+      return !isEmpty(this.experiment.metadata);
+    },
     deleteButtonInfo() {
       return {
         deletePath: this.experiment.path,
@@ -176,76 +180,94 @@ export default {
       }}</gl-button>
       <delete-button v-bind="deleteButtonInfo" />
     </model-experiments-header>
+    <section>
+      <registry-search
+        :filters="filters"
+        :sorting="sorting"
+        :sortable-fields="sortableFields"
+        @sorting:changed="updateSortingAndEmitUpdate"
+        @filter:changed="updateFilters"
+        @filter:submit="submitFilters"
+        @filter:clear="filters = []"
+      />
+
+      <div v-if="hasItems" class="gl-overflow-x-auto">
+        <gl-table-lite
+          :fields="fields"
+          :items="tableItems"
+          show-empty
+          small
+          class="gl-mt-0! ml-candidate-table"
+        >
+          <template #cell()="data">
+            <div>{{ data.value }}</div>
+          </template>
+
+          <template #cell(nameColumn)="data">
+            <gl-link :href="data.value.details_path">
+              <span v-if="data.value.name"> {{ data.value.name }}</span>
+              <span v-else class="gl-font-style-italic">{{ $options.i18n.NO_CANDIDATE_NAME }}</span>
+            </gl-link>
+          </template>
+
+          <template #cell(artifact)="data">
+            <gl-link v-if="data.value" :href="data.value" target="_blank">{{
+              $options.i18n.ARTIFACTS_LABEL
+            }}</gl-link>
+            <div v-else class="gl-font-style-italic gl-text-gray-500">
+              {{ $options.i18n.NO_ARTIFACT }}
+            </div>
+          </template>
+
+          <template #cell(created_at)="data">
+            <time-ago :time="data.value" />
+          </template>
+
+          <template #cell(user)="data">
+            <gl-link v-if="data.value" :href="data.value.path">@{{ data.value.username }}</gl-link>
+            <div v-else>{{ $options.i18n.NO_DATA_CONTENT }}</div>
+          </template>
+
+          <template #cell(ci_job)="data">
+            <gl-link v-if="data.value" :href="data.value.path" target="_blank">{{
+              data.value.name
+            }}</gl-link>
+            <div v-else class="gl-font-style-italic gl-text-gray-500">
+              {{ $options.i18n.NO_JOB }}
+            </div>
+          </template>
+        </gl-table-lite>
+      </div>
+
+      <gl-empty-state
+        v-else
+        :title="$options.i18n.EMPTY_STATE_TITLE_LABEL"
+        :primary-button-text="$options.i18n.CREATE_NEW_LABEL"
+        :primary-button-link="$options.constants.CREATE_CANDIDATE_HELP_PATH"
+        :svg-path="emptyStateSvgPath"
+        :svg-height="null"
+        :description="$options.i18n.EMPTY_STATE_DESCRIPTION_LABEL"
+        class="gl-py-8"
+      />
+
+      <keyset-pagination v-if="displayPagination" v-bind="pageInfo" />
+    </section>
+
+    <section>
+      <div class="experiment-metadata">
+        <h3 :class="$options.HEADER_CLASSES">{{ $options.i18n.METADATA_LABEL }}</h3>
+
+        <table v-if="hasMetadata">
+          <tbody>
+            <tr v-for="item in experiment.metadata" :key="item.name">
+              <td class="gl-font-weight-bold">{{ item.name }}</td>
+              <td>{{ item.value }}</td>
+            </tr>
+          </tbody>
+        </table>
 
-    <registry-search
-      :filters="filters"
-      :sorting="sorting"
-      :sortable-fields="sortableFields"
-      @sorting:changed="updateSortingAndEmitUpdate"
-      @filter:changed="updateFilters"
-      @filter:submit="submitFilters"
-      @filter:clear="filters = []"
-    />
-
-    <div v-if="hasItems" class="gl-overflow-x-auto">
-      <gl-table-lite
-        :fields="fields"
-        :items="tableItems"
-        show-empty
-        small
-        class="gl-mt-0! ml-candidate-table"
-      >
-        <template #cell()="data">
-          <div>{{ data.value }}</div>
-        </template>
-
-        <template #cell(nameColumn)="data">
-          <gl-link :href="data.value.details_path">
-            <span v-if="data.value.name"> {{ data.value.name }}</span>
-            <span v-else class="gl-font-style-italic">{{ $options.i18n.NO_CANDIDATE_NAME }}</span>
-          </gl-link>
-        </template>
-
-        <template #cell(artifact)="data">
-          <gl-link v-if="data.value" :href="data.value" target="_blank">{{
-            $options.i18n.ARTIFACTS_LABEL
-          }}</gl-link>
-          <div v-else class="gl-font-style-italic gl-text-gray-500">
-            {{ $options.i18n.NO_ARTIFACT }}
-          </div>
-        </template>
-
-        <template #cell(created_at)="data">
-          <time-ago :time="data.value" />
-        </template>
-
-        <template #cell(user)="data">
-          <gl-link v-if="data.value" :href="data.value.path">@{{ data.value.username }}</gl-link>
-          <div v-else>{{ $options.i18n.NO_DATA_CONTENT }}</div>
-        </template>
-
-        <template #cell(ci_job)="data">
-          <gl-link v-if="data.value" :href="data.value.path" target="_blank">{{
-            data.value.name
-          }}</gl-link>
-          <div v-else class="gl-font-style-italic gl-text-gray-500">
-            {{ $options.i18n.NO_JOB }}
-          </div>
-        </template>
-      </gl-table-lite>
-    </div>
-
-    <gl-empty-state
-      v-else
-      :title="$options.i18n.EMPTY_STATE_TITLE_LABEL"
-      :primary-button-text="$options.i18n.CREATE_NEW_LABEL"
-      :primary-button-link="$options.constants.CREATE_CANDIDATE_HELP_PATH"
-      :svg-path="emptyStateSvgPath"
-      :svg-height="null"
-      :description="$options.i18n.EMPTY_STATE_DESCRIPTION_LABEL"
-      class="gl-py-8"
-    />
-
-    <keyset-pagination v-if="displayPagination" v-bind="pageInfo" />
+        <div v-else class="gl-text-secondary">{{ $options.i18n.NO_METADATA_MESSAGE }}</div>
+      </div>
+    </section>
   </div>
 </template>
diff --git a/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/translations.js b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/translations.js
index 3af33f53fbd2fc8eae86e2e96fb084e0ccdb037d..1cf91ad2fc2d789c45215c6e42c4e085dce89873 100644
--- a/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/translations.js
+++ b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/translations.js
@@ -22,3 +22,5 @@ export const DELETE_EXPERIMENT_CONFIRMATION_MESSAGE = s__(
 export const DELETE_EXPERIMENT_PRIMARY_ACTION_LABEL = s__('MlExperimentTracking|Delete experiment');
 export const DELETE_EXPERIMENT_MODAL_TITLE = s__('MLExperimentTracking|Delete experiment?');
 export const DOWNLOAD_AS_CSV_LABEL = s__('MlExperimentTracking|Download as CSV');
+export const METADATA_LABEL = s__('MlExperimentTracking|Experiment metadata');
+export const NO_METADATA_MESSAGE = s__('MlExperimentTracking|No logged experiment metadata');
diff --git a/app/assets/stylesheets/page_bundles/ml_experiment_tracking.scss b/app/assets/stylesheets/page_bundles/ml_experiment_tracking.scss
index 82fb631036c3bec82d0b9dbcf2cc21e52eb648de..758bc5a72efac06208830915d00aeadf1ee8a25b 100644
--- a/app/assets/stylesheets/page_bundles/ml_experiment_tracking.scss
+++ b/app/assets/stylesheets/page_bundles/ml_experiment_tracking.scss
@@ -13,6 +13,7 @@ table.ml-candidate-table {
   }
 }
 
+.experiment-metadata table,
 table.candidate-details {
   td {
     padding: $gl-spacing-scale-3 $gl-spacing-scale-3 $gl-spacing-scale-3 0;
diff --git a/app/helpers/projects/ml/experiments_helper.rb b/app/helpers/projects/ml/experiments_helper.rb
index 6c7b6eb6fbcbc8c230e8732fa376b17ab1bc8f7b..e858f85c0b31be781530677efb1de6d8a576888c 100644
--- a/app/helpers/projects/ml/experiments_helper.rb
+++ b/app/helpers/projects/ml/experiments_helper.rb
@@ -8,6 +8,7 @@ module ExperimentsHelper
       def experiment_as_data(experiment)
         data = {
           name: experiment.name,
+          metadata: experiment.metadata,
           path: link_to_experiment(experiment.project, experiment)
         }
 
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index d4bc0d4dc4e2a35f7624be4af811b45a6b31bc4a..41268fb9ff8a6f0c8cd0b44f304f2ed135637721 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -32212,6 +32212,9 @@ msgstr ""
 msgid "MlExperimentTracking|Experiment"
 msgstr ""
 
+msgid "MlExperimentTracking|Experiment metadata"
+msgstr ""
+
 msgid "MlExperimentTracking|Experiment removed"
 msgstr ""
 
@@ -32251,6 +32254,9 @@ msgstr ""
 msgid "MlExperimentTracking|No candidates logged for the query. Create new candidates using the MLflow client."
 msgstr ""
 
+msgid "MlExperimentTracking|No logged experiment metadata"
+msgstr ""
+
 msgid "MlExperimentTracking|No name"
 msgstr ""
 
diff --git a/spec/frontend/ml/experiment_tracking/routes/experiments/show/ml_experiments_show_spec.js b/spec/frontend/ml/experiment_tracking/routes/experiments/show/ml_experiments_show_spec.js
index 2dd178883054a4c2d1e4b002c07fbc36654cd81d..d62982adeb8b10674ec53b65d6efe261eb140070 100644
--- a/spec/frontend/ml/experiment_tracking/routes/experiments/show/ml_experiments_show_spec.js
+++ b/spec/frontend/ml/experiment_tracking/routes/experiments/show/ml_experiments_show_spec.js
@@ -7,7 +7,13 @@ import RegistrySearch from '~/vue_shared/components/registry/registry_search.vue
 import Pagination from '~/vue_shared/components/incubation/pagination.vue';
 import setWindowLocation from 'helpers/set_window_location_helper';
 import * as urlHelpers from '~/lib/utils/url_utility';
-import { MOCK_START_CURSOR, MOCK_PAGE_INFO, MOCK_CANDIDATES, MOCK_EXPERIMENT } from './mock_data';
+import {
+  MOCK_START_CURSOR,
+  MOCK_PAGE_INFO,
+  MOCK_CANDIDATES,
+  MOCK_EXPERIMENT,
+  MOCK_EXPERIMENT_METADATA,
+} from './mock_data';
 
 describe('MlExperimentsShow', () => {
   let wrapper;
@@ -29,6 +35,17 @@ describe('MlExperimentsShow', () => {
     createWrapper(MOCK_CANDIDATES, ['rmse', 'auc', 'mae'], ['l1_ratio'], pageInfo);
   };
 
+  const createWrapperWithExperimentMetadata = () => {
+    createWrapper(
+      [],
+      [],
+      [],
+      MOCK_PAGE_INFO,
+      { ...MOCK_EXPERIMENT, metadata: MOCK_EXPERIMENT_METADATA },
+      'path',
+    );
+  };
+
   const findPagination = () => wrapper.findComponent(Pagination);
   const findEmptyState = () => wrapper.findComponent(GlEmptyState);
   const findRegistrySearch = () => wrapper.findComponent(RegistrySearch);
@@ -40,6 +57,10 @@ describe('MlExperimentsShow', () => {
   const findExperimentHeader = () => wrapper.findComponent(ModelExperimentsHeader);
   const findDeleteButton = () => wrapper.findComponent(DeleteButton);
   const findDownloadButton = () => findExperimentHeader().findComponent(GlButton);
+  const findMetadataTableRow = (idx) => wrapper.findAll('.experiment-metadata tbody > tr').at(idx);
+  const findMetadataTableColumn = (row, col) => findMetadataTableRow(row).findAll('td').at(col);
+  const findMetadataHeader = () => wrapper.find('.experiment-metadata h3');
+  const findMetadataEmptyState = () => wrapper.find('.experiment-metadata .gl-text-secondary');
 
   const hrefInRowAndColumn = (row, col) =>
     findColumnInRow(row, col).findComponent(GlLink).attributes().href;
@@ -318,4 +339,27 @@ describe('MlExperimentsShow', () => {
       });
     });
   });
+
+  describe('Experiments metadata', () => {
+    it('has correct header', () => {
+      createWrapper();
+
+      expect(findMetadataHeader().text()).toBe('Experiment metadata');
+    });
+
+    it('shows empty state if there is no metadata', () => {
+      createWrapper();
+
+      expect(findMetadataEmptyState().text()).toBe('No logged experiment metadata');
+    });
+
+    it('shows the metadata', () => {
+      createWrapperWithExperimentMetadata();
+
+      MOCK_EXPERIMENT_METADATA.forEach((metadata, idx) => {
+        expect(findMetadataTableColumn(idx, 0).text()).toContain(metadata.name);
+        expect(findMetadataTableColumn(idx, 1).text()).toContain(metadata.value);
+      });
+    });
+  });
 });
diff --git a/spec/frontend/ml/experiment_tracking/routes/experiments/show/mock_data.js b/spec/frontend/ml/experiment_tracking/routes/experiments/show/mock_data.js
index 4a606be8da6f82fc0a6d0585dbc318ec2780d262..33b3a343c7f3dfbb065ab58e06bb6bbf5f36fc96 100644
--- a/spec/frontend/ml/experiment_tracking/routes/experiments/show/mock_data.js
+++ b/spec/frontend/ml/experiment_tracking/routes/experiments/show/mock_data.js
@@ -7,7 +7,30 @@ export const MOCK_PAGE_INFO = {
   hasPreviousPage: true,
 };
 
-export const MOCK_EXPERIMENT = { name: 'experiment', path: '/path/to/experiment' };
+export const MOCK_EXPERIMENT = {
+  name: 'experiment',
+  metadata: [],
+  path: '/path/to/experiment',
+};
+
+export const MOCK_EXPERIMENT_METADATA = [
+  {
+    id: 1,
+    created_at: '2024-03-20T16:19:23.843Z',
+    updated_at: '2024-03-20T16:19:23.843Z',
+    experiment_id: 1,
+    name: 'metadata_1',
+    value: 'a',
+  },
+  {
+    id: 2,
+    created_at: '2024-03-20T16:19:23.848Z',
+    updated_at: '2024-03-20T16:19:23.848Z',
+    experiment_id: 1,
+    name: 'metadata_2',
+    value: 'b',
+  },
+];
 
 export const MOCK_CANDIDATES = [
   {
diff --git a/spec/helpers/projects/ml/experiments_helper_spec.rb b/spec/helpers/projects/ml/experiments_helper_spec.rb
index 9ac518f664d4253df15b6d7b34d147124a73f09f..c7fc75c3d90cfa30ebb15cbc44612a10cf9a58c8 100644
--- a/spec/helpers/projects/ml/experiments_helper_spec.rb
+++ b/spec/helpers/projects/ml/experiments_helper_spec.rb
@@ -106,9 +106,11 @@
     subject { Gitlab::Json.parse(helper.experiment_as_data(experiment)) }
 
     it do
-      is_expected.to eq(
-        { 'name' => experiment.name, 'path' => "/#{project.full_path}/-/ml/experiments/#{experiment.iid}" }
-      )
+      is_expected.to eq({
+        'name' => experiment.name,
+        'metadata' => experiment.metadata,
+        'path' => "/#{project.full_path}/-/ml/experiments/#{experiment.iid}"
+      })
     end
   end