diff --git a/integrations/api_issue_milestone_test.go b/integrations/api_issue_milestone_test.go
index 4cc574b9eb..b9942d9a3c 100644
--- a/integrations/api_issue_milestone_test.go
+++ b/integrations/api_issue_milestone_test.go
@@ -61,6 +61,11 @@ func TestAPIIssuesMilestone(t *testing.T) {
 	DecodeJSON(t, resp, &apiMilestones)
 	assert.Len(t, apiMilestones, 4)
 
+	req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/milestones/%s?token=%s", owner.Name, repo.Name, apiMilestones[2].Title, token))
+	resp = session.MakeRequest(t, req, http.StatusOK)
+	DecodeJSON(t, resp, &apiMilestone)
+	assert.EqualValues(t, apiMilestones[2], apiMilestone)
+
 	req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/milestones?state=%s&name=%s&token=%s", owner.Name, repo.Name, "all", "milestone2", token))
 	resp = session.MakeRequest(t, req, http.StatusOK)
 	DecodeJSON(t, resp, &apiMilestones)
diff --git a/routers/api/v1/repo/milestone.go b/routers/api/v1/repo/milestone.go
index f6f6b29465..5a250dbd80 100644
--- a/routers/api/v1/repo/milestone.go
+++ b/routers/api/v1/repo/milestone.go
@@ -7,6 +7,7 @@ package repo
 
 import (
 	"net/http"
+	"strconv"
 	"time"
 
 	"code.gitea.io/gitea/models"
@@ -73,7 +74,7 @@ func ListMilestones(ctx *context.APIContext) {
 	ctx.JSON(http.StatusOK, &apiMilestones)
 }
 
-// GetMilestone get a milestone for a repository
+// GetMilestone get a milestone for a repository by ID and if not available by name
 func GetMilestone(ctx *context.APIContext) {
 	// swagger:operation GET /repos/{owner}/{repo}/milestones/{id} issue issueGetMilestone
 	// ---
@@ -93,23 +94,18 @@ func GetMilestone(ctx *context.APIContext) {
 	//   required: true
 	// - name: id
 	//   in: path
-	//   description: id of the milestone
-	//   type: integer
-	//   format: int64
+	//   description: the milestone to get, identified by ID and if not available by name
+	//   type: string
 	//   required: true
 	// responses:
 	//   "200":
 	//     "$ref": "#/responses/Milestone"
 
-	milestone, err := models.GetMilestoneByRepoID(ctx.Repo.Repository.ID, ctx.ParamsInt64(":id"))
-	if err != nil {
-		if models.IsErrMilestoneNotExist(err) {
-			ctx.NotFound()
-		} else {
-			ctx.Error(http.StatusInternalServerError, "GetMilestoneByRepoID", err)
-		}
+	milestone := getMilestoneByIDOrName(ctx)
+	if ctx.Written() {
 		return
 	}
+
 	ctx.JSON(http.StatusOK, convert.ToAPIMilestone(milestone))
 }
 
@@ -165,7 +161,7 @@ func CreateMilestone(ctx *context.APIContext, form api.CreateMilestoneOption) {
 	ctx.JSON(http.StatusCreated, convert.ToAPIMilestone(milestone))
 }
 
-// EditMilestone modify a milestone for a repository
+// EditMilestone modify a milestone for a repository by ID and if not available by name
 func EditMilestone(ctx *context.APIContext, form api.EditMilestoneOption) {
 	// swagger:operation PATCH /repos/{owner}/{repo}/milestones/{id} issue issueEditMilestone
 	// ---
@@ -187,9 +183,8 @@ func EditMilestone(ctx *context.APIContext, form api.EditMilestoneOption) {
 	//   required: true
 	// - name: id
 	//   in: path
-	//   description: id of the milestone
-	//   type: integer
-	//   format: int64
+	//   description: the milestone to edit, identified by ID and if not available by name
+	//   type: string
 	//   required: true
 	// - name: body
 	//   in: body
@@ -199,13 +194,8 @@ func EditMilestone(ctx *context.APIContext, form api.EditMilestoneOption) {
 	//   "200":
 	//     "$ref": "#/responses/Milestone"
 
-	milestone, err := models.GetMilestoneByRepoID(ctx.Repo.Repository.ID, ctx.ParamsInt64(":id"))
-	if err != nil {
-		if models.IsErrMilestoneNotExist(err) {
-			ctx.NotFound()
-		} else {
-			ctx.Error(http.StatusInternalServerError, "GetMilestoneByRepoID", err)
-		}
+	milestone := getMilestoneByIDOrName(ctx)
+	if ctx.Written() {
 		return
 	}
 
@@ -231,7 +221,7 @@ func EditMilestone(ctx *context.APIContext, form api.EditMilestoneOption) {
 	ctx.JSON(http.StatusOK, convert.ToAPIMilestone(milestone))
 }
 
-// DeleteMilestone delete a milestone for a repository
+// DeleteMilestone delete a milestone for a repository by ID and if not available by name
 func DeleteMilestone(ctx *context.APIContext) {
 	// swagger:operation DELETE /repos/{owner}/{repo}/milestones/{id} issue issueDeleteMilestone
 	// ---
@@ -249,17 +239,49 @@ func DeleteMilestone(ctx *context.APIContext) {
 	//   required: true
 	// - name: id
 	//   in: path
-	//   description: id of the milestone to delete
-	//   type: integer
-	//   format: int64
+	//   description: the milestone to delete, identified by ID and if not available by name
+	//   type: string
 	//   required: true
 	// responses:
 	//   "204":
 	//     "$ref": "#/responses/empty"
 
-	if err := models.DeleteMilestoneByRepoID(ctx.Repo.Repository.ID, ctx.ParamsInt64(":id")); err != nil {
+	m := getMilestoneByIDOrName(ctx)
+	if ctx.Written() {
+		return
+	}
+
+	if err := models.DeleteMilestoneByRepoID(ctx.Repo.Repository.ID, m.ID); err != nil {
 		ctx.Error(http.StatusInternalServerError, "DeleteMilestoneByRepoID", err)
 		return
 	}
 	ctx.Status(http.StatusNoContent)
 }
+
+// getMilestoneByIDOrName get milestone by ID and if not available by name
+func getMilestoneByIDOrName(ctx *context.APIContext) *models.Milestone {
+	mile := ctx.Params(":id")
+	mileID, _ := strconv.ParseInt(mile, 0, 64)
+
+	if mileID != 0 {
+		milestone, err := models.GetMilestoneByRepoID(ctx.Repo.Repository.ID, mileID)
+		if err == nil {
+			return milestone
+		} else if !models.IsErrMilestoneNotExist(err) {
+			ctx.Error(http.StatusInternalServerError, "GetMilestoneByRepoID", err)
+			return nil
+		}
+	}
+
+	milestone, err := models.GetMilestoneByRepoIDANDName(ctx.Repo.Repository.ID, mile)
+	if err != nil {
+		if models.IsErrMilestoneNotExist(err) {
+			ctx.NotFound()
+			return nil
+		}
+		ctx.Error(http.StatusInternalServerError, "GetMilestoneByRepoID", err)
+		return nil
+	}
+
+	return milestone
+}
diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl
index a5840f2bab..4b78b40dd2 100644
--- a/templates/swagger/v1_json.tmpl
+++ b/templates/swagger/v1_json.tmpl
@@ -6353,9 +6353,8 @@
             "required": true
           },
           {
-            "type": "integer",
-            "format": "int64",
-            "description": "id of the milestone",
+            "type": "string",
+            "description": "the milestone to get, identified by ID and if not available by name",
             "name": "id",
             "in": "path",
             "required": true
@@ -6389,9 +6388,8 @@
             "required": true
           },
           {
-            "type": "integer",
-            "format": "int64",
-            "description": "id of the milestone to delete",
+            "type": "string",
+            "description": "the milestone to delete, identified by ID and if not available by name",
             "name": "id",
             "in": "path",
             "required": true
@@ -6431,9 +6429,8 @@
             "required": true
           },
           {
-            "type": "integer",
-            "format": "int64",
-            "description": "id of the milestone",
+            "type": "string",
+            "description": "the milestone to edit, identified by ID and if not available by name",
             "name": "id",
             "in": "path",
             "required": true