diff --git a/app/assets/javascripts/ml/experiment_tracking/components/performance_graph.vue b/app/assets/javascripts/ml/experiment_tracking/components/performance_graph.vue
index f0fc346e43a965c718e781a2d0f659ace7e0c970..0457c722d83eaf4c3d9c8d34166cd303ec1383da 100644
--- a/app/assets/javascripts/ml/experiment_tracking/components/performance_graph.vue
+++ b/app/assets/javascripts/ml/experiment_tracking/components/performance_graph.vue
@@ -1,10 +1,12 @@
 <script>
 import { GlLineChart } from '@gitlab/ui/dist/charts';
+import { GlEmptyState } from '@gitlab/ui';
 import { s__ } from '~/locale';
+import { CREATE_EXPERIMENT_HELP_PATH } from '~/ml/experiment_tracking/routes/experiments/index/constants';
 
 export default {
   name: 'PerformanceGraph',
-  components: { GlLineChart },
+  components: { GlLineChart, GlEmptyState },
   props: {
     candidates: {
       type: Array,
@@ -14,6 +16,11 @@ export default {
       type: Array,
       required: true,
     },
+    emptyStateSvgPath: {
+      type: String,
+      required: false,
+      default: '',
+    },
   },
   data() {
     return {
@@ -24,6 +31,11 @@ export default {
   i18n: {
     xAxisLabel: s__('ExperimentTracking|Candidate'),
     yAxisLabel: s__('ExperimentTracking|Metric value'),
+    createNewCandidateLabel: s__('ExperimentTracking|Create candidate using MLflow'),
+    emptyStateLabel: s__('ExperimentTracking|No candidates'),
+    emptyStateDescriptionLabel: s__(
+      'ExperimentTracking|Performance graph will be shown when candidates with logged metrics are available',
+    ),
   },
   computed: {
     graphData() {
@@ -55,6 +67,12 @@ export default {
         toolbox: { show: true },
       };
     },
+    showGraph() {
+      return this.candidates.length > 0 && this.metricNames.length > 0;
+    },
+  },
+  constants: {
+    CREATE_EXPERIMENT_HELP_PATH,
   },
   methods: {
     formatTooltipText(params) {
@@ -70,6 +88,7 @@ export default {
 
 <template>
   <gl-line-chart
+    v-if="showGraph"
     :data="graphData"
     :option="graphOptions"
     show-legend
@@ -87,4 +106,14 @@ export default {
       </div>
     </template>
   </gl-line-chart>
+  <gl-empty-state
+    v-else
+    :title="$options.i18n.emptyStateLabel"
+    :secondary-button-text="$options.i18n.createNewCandidateLabel"
+    :secondary-button-link="$options.constants.CREATE_EXPERIMENT_HELP_PATH"
+    :svg-path="emptyStateSvgPath"
+    :svg-height="null"
+    :description="$options.i18n.emptyStateDescriptionLabel"
+    class="gl-py-8"
+  />
 </template>
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index e6a28a0a7271e6bb0d3be0fa0bcf3dd79d41982e..e1b600752a8d0f055b38cc421fcd87c12c682d6b 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -22932,12 +22932,21 @@ msgstr ""
 msgid "ExperimentTracking|Candidate"
 msgstr ""
 
+msgid "ExperimentTracking|Create candidate using MLflow"
+msgstr ""
+
 msgid "ExperimentTracking|Metric value"
 msgstr ""
 
+msgid "ExperimentTracking|No candidates"
+msgstr ""
+
 msgid "ExperimentTracking|Performance"
 msgstr ""
 
+msgid "ExperimentTracking|Performance graph will be shown when candidates with logged metrics are available"
+msgstr ""
+
 msgid "Experiments"
 msgstr ""
 
diff --git a/spec/frontend/ml/experiment_tracking/components/performance_graph_spec.js b/spec/frontend/ml/experiment_tracking/components/performance_graph_spec.js
index 48f8f2a94b2b46c2c817e49f47068275ce24b609..be67912f9cec466137c594ea86afa94cc0942ea0 100644
--- a/spec/frontend/ml/experiment_tracking/components/performance_graph_spec.js
+++ b/spec/frontend/ml/experiment_tracking/components/performance_graph_spec.js
@@ -1,4 +1,5 @@
 import { GlLineChart } from '@gitlab/ui/dist/charts';
+import { GlEmptyState } from '@gitlab/ui';
 import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
 import PerformanceGraph from '~/ml/experiment_tracking/components/performance_graph.vue';
 import { MOCK_CANDIDATES } from '../routes/experiments/show/mock_data';
@@ -12,12 +13,14 @@ describe('PerformanceGraph', () => {
       propsData: {
         candidates,
         metricNames,
+        emptyStateSvgPath: 'illustrations/status/status-new-md.svg',
       },
     });
   };
 
   const findGraph = () => wrapper.findComponent(PerformanceGraph);
   const findLineChart = () => findGraph().findComponent(GlLineChart);
+  const findEmptyState = () => wrapper.findComponent(GlEmptyState);
 
   describe('rendering', () => {
     it('renders the component', () => {
@@ -25,6 +28,7 @@ describe('PerformanceGraph', () => {
 
       expect(findGraph().props('candidates')).toEqual(MOCK_CANDIDATES);
       expect(findGraph().props('metricNames')).toEqual(MOCK_METRICS);
+      expect(findEmptyState().exists()).toBe(false);
     });
 
     it('renders the correct data', () => {
@@ -39,4 +43,27 @@ describe('PerformanceGraph', () => {
       expect(findLineChart().props('data')[2].data.length).toBe(1);
     });
   });
+
+  describe('empty state', () => {
+    it('should show empty state if candidates are missing', () => {
+      createWrapper([], MOCK_METRICS);
+
+      expect(findLineChart().exists()).toBe(false);
+      expect(findEmptyState().exists()).toBe(true);
+    });
+
+    it('should show empty state if metric names are missing', () => {
+      createWrapper(MOCK_CANDIDATES, []);
+
+      expect(findLineChart().exists()).toBe(false);
+      expect(findEmptyState().exists()).toBe(true);
+    });
+
+    it('should show empty state if candidates and metric names are missing', () => {
+      createWrapper([], []);
+
+      expect(findLineChart().exists()).toBe(false);
+      expect(findEmptyState().exists()).toBe(true);
+    });
+  });
 });