diff --git a/app/graphql/mutations/ml/models/delete.rb b/app/graphql/mutations/ml/models/delete.rb
new file mode 100644
index 0000000000000000000000000000000000000000..6791eddab295659dff7010cdfd070dcfd894bc44
--- /dev/null
+++ b/app/graphql/mutations/ml/models/delete.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+module Mutations
+  module Ml
+    module Models
+      class Delete < Base
+        graphql_name 'MlModelDelete'
+
+        include FindsProject
+
+        argument :id, ::Types::GlobalIDType[::Ml::Model],
+          required: true,
+          description: 'Global ID of the model to be deleted.'
+
+        def resolve(**args)
+          project = authorized_find!(args[:project_path])
+
+          model = ::Ml::Model.by_project_id_and_id(project.id, args[:id].model_id)
+
+          return { errors: ['Model not found'] } unless model
+
+          result = ::Ml::DestroyModelService.new(model, current_user).execute
+
+          {
+            model: result.payload[:model],
+            errors: result.errors
+          }
+        end
+      end
+    end
+  end
+end
diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb
index fd8233d5ebf01daf929548614653fa10d3d732d3..96601c035a036c176d40f1416d673759a1c1a292 100644
--- a/app/graphql/types/mutation_type.rb
+++ b/app/graphql/types/mutation_type.rb
@@ -210,6 +210,7 @@ class MutationType < BaseObject
     mount_mutation Mutations::Admin::AbuseReportLabels::Create, alpha: { milestone: '16.4' }
     mount_mutation Mutations::Ml::Models::Create, alpha: { milestone: '16.8' }
     mount_mutation Mutations::Ml::Models::Destroy, alpha: { milestone: '16.10' }
+    mount_mutation Mutations::Ml::Models::Delete, alpha: { milestone: '17.0' }
     mount_mutation Mutations::Ml::ModelVersions::Delete, alpha: { milestone: '17.0' }
     mount_mutation Mutations::BranchRules::Delete, alpha: { milestone: '16.9' }
   end
diff --git a/app/services/ml/destroy_model_service.rb b/app/services/ml/destroy_model_service.rb
index 29df70b3c37d64e5c1e918de27b9af3646e7cc3d..f2a33d58cd88282838ba6dd885ff0fd802e56c34 100644
--- a/app/services/ml/destroy_model_service.rb
+++ b/app/services/ml/destroy_model_service.rb
@@ -8,14 +8,14 @@ def initialize(model, user)
     end
 
     def execute
-      return error unless @model.destroy
-
       package_deletion_result = ::Packages::MarkPackagesForDestructionService.new(
         packages: @model.all_packages,
         current_user: @user
       ).execute
 
-      return packages_not_deleted if package_deletion_result.error?
+      return packages_not_deleted(package_deletion_result.message) if package_deletion_result.error?
+
+      return error unless @model.destroy
 
       success
     end
@@ -23,15 +23,19 @@ def execute
     private
 
     def success
-      ServiceResponse.success(message: _('Model was successfully deleted'))
+      ServiceResponse.success(payload: payload)
     end
 
     def error
-      ServiceResponse.error(message: _('Failed to delete model'))
+      ServiceResponse.error(message: @model.errors.full_messages, payload: payload)
+    end
+
+    def packages_not_deleted(error_message)
+      ServiceResponse.error(message: error_message, payload: payload)
     end
 
-    def packages_not_deleted
-      ServiceResponse.success(message: _('Model deleted but failed to remove associated packages'))
+    def payload
+      { model: @model }
     end
   end
 end
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 75d7f9b959439b11cecc4de3e7c2f2eae37c22b7..3950ee66bbd33db4c08537a4652a36b7aa90f375 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -6593,6 +6593,30 @@ Input type: `MlModelCreateInput`
 | <a id="mutationmlmodelcreateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
 | <a id="mutationmlmodelcreatemodel"></a>`model` | [`MlModel`](#mlmodel) | Model after mutation. |
 
+### `Mutation.mlModelDelete`
+
+DETAILS:
+**Introduced** in GitLab 17.0.
+**Status**: Experiment.
+
+Input type: `MlModelDeleteInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationmlmodeldeleteclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationmlmodeldeleteid"></a>`id` | [`MlModelID!`](#mlmodelid) | Global ID of the model to be deleted. |
+| <a id="mutationmlmodeldeleteprojectpath"></a>`projectPath` | [`ID!`](#id) | Project the model to mutate is in. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationmlmodeldeleteclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationmlmodeldeleteerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+| <a id="mutationmlmodeldeletemodel"></a>`model` | [`MlModel`](#mlmodel) | Model after mutation. |
+
 ### `Mutation.mlModelDestroy`
 
 DETAILS:
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index c6beca4fa7c0b828f369927571718b34891bb278..221a5594cb768dc15182f6d7ad199284a9849464 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -21562,9 +21562,6 @@ msgstr ""
 msgid "Failed to delete custom emoji. Please try again."
 msgstr ""
 
-msgid "Failed to delete model"
-msgstr ""
-
 msgid "Failed to deploy to"
 msgstr ""
 
@@ -33120,9 +33117,6 @@ msgstr ""
 msgid "Modal|Close"
 msgstr ""
 
-msgid "Model deleted but failed to remove associated packages"
-msgstr ""
-
 msgid "Model experiments"
 msgstr ""
 
@@ -33132,9 +33126,6 @@ msgstr ""
 msgid "Model version not found"
 msgstr ""
 
-msgid "Model was successfully deleted"
-msgstr ""
-
 msgid "ModelRegistry|Model registry"
 msgstr ""
 
diff --git a/spec/requests/api/graphql/mutations/ml/models/delete_spec.rb b/spec/requests/api/graphql/mutations/ml/models/delete_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..b502bff52ef0f25b6eb4447a729c82d9ee138bd3
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/ml/models/delete_spec.rb
@@ -0,0 +1,110 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Deleting a model', feature_category: :mlops do
+  using RSpec::Parameterized::TableSyntax
+
+  include GraphqlHelpers
+
+  let_it_be_with_reload(:model) { create(:ml_models) }
+  let_it_be(:user) { create(:user) }
+
+  let(:project) { model.project }
+  let(:id) { model.to_global_id.to_s }
+
+  let(:query) do
+    <<~GQL
+      model {
+        id
+      }
+      errors
+    GQL
+  end
+
+  let(:params) { { project_path: project.full_path, id: id } }
+  let(:mutation) { graphql_mutation(:ml_model_delete, params, query) }
+  let(:mutation_response) { graphql_mutation_response(:ml_model_delete) }
+
+  shared_examples 'destroying the model' do
+    it 'destroys model' do
+      expect(::Ml::DestroyModelService).to receive(:new).with(model, user).and_call_original
+
+      expect { mutation_request }.to change { ::Ml::Model.count }.by(-1)
+      expect(mutation_response['model']).to eq({ "id" => id })
+    end
+
+    it_behaves_like 'returning response status', :success
+  end
+
+  shared_examples 'denying the mutation request' do
+    it 'does not delete the model' do
+      expect(::Ml::DestroyModelService).not_to receive(:new)
+
+      expect { mutation_request }.to not_change { ::Ml::Model.count }
+
+      expect(mutation_response).to be_nil
+      expect_graphql_errors_to_include("The resource that you are attempting to access does not exist or you don't " \
+                                       "have permission to perform this action")
+    end
+
+    it_behaves_like 'returning response status', :success
+  end
+
+  shared_examples 'model was not found' do
+    it 'does not delete the model' do
+      expect(::Ml::DestroyModelService).not_to receive(:new)
+
+      expect { mutation_request }.to not_change { ::Ml::Model.count }
+
+      expect(mutation_response["errors"]).to match_array(['Model not found'])
+    end
+
+    it_behaves_like 'returning response status', :success
+  end
+
+  describe 'post graphql mutation' do
+    subject(:mutation_request) { post_graphql_mutation(mutation, current_user: user) }
+
+    context 'with valid id' do
+      where(:user_role, :mutation_behavior) do
+        :reporter   | 'destroying the model'
+        :guest      | 'denying the mutation request'
+      end
+
+      with_them do
+        before do
+          project.public_send("add_#{user_role}", user)
+        end
+
+        it_behaves_like params[:mutation_behavior]
+      end
+    end
+
+    context 'with authorized user' do
+      before do
+        project.add_maintainer(user)
+      end
+
+      context 'with invalid id' do
+        let(:params) { { project_path: project.full_path, id: "gid://gitlab/Ml::Model/#{non_existing_record_id}" } }
+
+        it_behaves_like 'model was not found'
+      end
+
+      context 'when an error occurs' do
+        it 'returns the errors in the response' do
+          allow_next_found_instance_of(::Ml::Model) do |model|
+            allow(model).to receive(:destroy).and_return(nil)
+            errors = ActiveModel::Errors.new(model).tap { |e| e.add(:id, 'some error') }
+            allow(model).to receive(:errors).and_return(errors)
+          end
+
+          mutation_request
+
+          expect(mutation_response['errors']).to match_array(['Id some error'])
+        end
+      end
+    end
+  end
+end
diff --git a/spec/requests/api/graphql/mutations/ml/models/destroy_spec.rb b/spec/requests/api/graphql/mutations/ml/models/destroy_spec.rb
index bd849f30c4e320c3208829ab322151c01897d738..7cf4cbf14dc4d294c0abf719aebe459992f3f62b 100644
--- a/spec/requests/api/graphql/mutations/ml/models/destroy_spec.rb
+++ b/spec/requests/api/graphql/mutations/ml/models/destroy_spec.rb
@@ -106,11 +106,13 @@
         it 'returns the errors in the response' do
           allow_next_found_instance_of(::Ml::Model) do |model|
             allow(model).to receive(:destroy).and_return(nil)
+            errors = ActiveModel::Errors.new(model).tap { |e| e.add(:id, 'some error') }
+            allow(model).to receive(:errors).and_return(errors)
           end
 
           mutation_request
 
-          expect(mutation_response['errors']).to match_array(['Failed to delete model'])
+          expect(mutation_response['errors']).to match_array(['Id some error'])
         end
       end
     end
diff --git a/spec/services/ml/destroy_model_service_spec.rb b/spec/services/ml/destroy_model_service_spec.rb
index fcbafc0a57145cb9b2d1086c70dbc4e7ef4ddfa7..0e21d9dc39c9b58ae52a95d7d8e3528648a5bcbb 100644
--- a/spec/services/ml/destroy_model_service_spec.rb
+++ b/spec/services/ml/destroy_model_service_spec.rb
@@ -36,14 +36,14 @@
 
         before do
           allow_next_instance_of(Packages::MarkPackagesForDestructionService) do |instance|
-            allow(instance).to receive(:execute).and_return ServiceResponse.error(message: "")
+            allow(instance).to receive(:execute).and_return ServiceResponse.error(message: "An error")
           end
         end
 
         it 'returns success with warning', :aggregate_failures do
-          expect { service_result }.to change { Ml::Model.count }.by(-1).and change { Ml::ModelVersion.count }.by(-1)
-          expect(service_result).to be_success
-          expect(service_result.message).to eq('Model deleted but failed to remove associated packages')
+          expect { service_result }.not_to change { Ml::Model.count }
+          expect(service_result).to be_error
+          expect(service_result.message).to eq("An error")
         end
       end
     end