diff --git a/controllers/meeting.js b/controllers/meeting.js
index 27532ee5a66d273bd913ab86566dce2ed7ea2d68..0ab9479914e7be561c4692ded83311f50ba0438b 100644
--- a/controllers/meeting.js
+++ b/controllers/meeting.js
@@ -1,10 +1,12 @@
 const bcrypt = require('bcrypt');
 const { Meeting, Participant, Schedule } = require('../models');
+const meetingRepositotry = require('../repository/meeting');
 const {
   createMeetingNotFoundError,
   createMeetingIsAlreadyClosedError,
   createPasswordNotMatchedError,
   createPasswordIsNullError,
+  createMostConfirmedTimeNotFoundError,
 } = require('../errors/meetingErrors');
 const MeetingResponse = require('../dto/response/meetingResponse');
 const MeetingWithParticipantsResponse = require('../dto/response/meetingWithParticipantsResponse');
@@ -175,6 +177,19 @@ exports.getMeetingDetailById = async (req, res, next) => {
   }
 };
 
+exports.getMostConfirmedTime = async (req, res, next) => {
+  const { purpose } = req.query;
+  if (!purpose) {
+    return res.status(400).json({ message: 'Purpose is required' });
+  }
+  try {
+    const result = await meetingRepositotry.getMostConfirmedTime(purpose);
+    return res.json(result);
+  } catch (error) {
+    return next(error);
+  }
+};
+
 function validateMeetingIsNotClosed(meeting) {
   if (meeting.isClosed === true) {
     throw createMeetingIsAlreadyClosedError();
diff --git a/errors/meetingErrors.js b/errors/meetingErrors.js
index 5b1e71f6e24747ef9222b084a60ab23f1fa19c0f..b52602fdbb9a26b64aca065a68418ef837c1c486 100644
--- a/errors/meetingErrors.js
+++ b/errors/meetingErrors.js
@@ -21,3 +21,11 @@ exports.createPasswordIsNullError = () => {
   error.status = 400;
   return error;
 };
+
+exports.createMostConfirmedTimeNotFoundError = () => {
+  const error = new Error(
+    '데이터가 충분하지 않아 통계 정보를 찾을 수 없습니다.',
+  );
+  error.status = 404;
+  return error;
+};
diff --git a/repository/meeting.js b/repository/meeting.js
new file mode 100644
index 0000000000000000000000000000000000000000..d634c3f7d23040d68ee16b950c3591aba33e1d14
--- /dev/null
+++ b/repository/meeting.js
@@ -0,0 +1,31 @@
+const Sequelize = require('sequelize');
+const { sequelize } = require('../models/index');
+const {
+  createMostConfirmedTimeNotFoundError,
+} = require('../errors/meetingErrors');
+
+exports.getMostConfirmedTime = async (purpose) => {
+  const query = `
+      SELECT EXTRACT(HOUR FROM m.confirmed_time) AS confirmed_time_hour,
+             COUNT(1)                            AS confirmed_time_count
+      FROM meetings m
+      WHERE m.is_closed
+        AND m.purpose = :purpose
+        AND m.confirmed_time IS NOT NULL
+      GROUP BY confirmed_time_hour
+      ORDER BY confirmed_time_count DESC;
+  `;
+  const params = {
+    replacements: { purpose },
+    type: Sequelize.QueryTypes.SELECT,
+    plain: true,
+  };
+  const result = await sequelize.query(query, params);
+  if (!result) {
+    throw createMostConfirmedTimeNotFoundError();
+  }
+  return {
+    hour: result.confirmed_time_hour,
+    count: result.confirmed_time_count,
+  };
+};
diff --git a/routes/meeting.js b/routes/meeting.js
index d32bd4e17c79b693901b85a84a9129417b2df481..4ad462d02083a3e5f04147876ece5543d124d2b6 100644
--- a/routes/meeting.js
+++ b/routes/meeting.js
@@ -5,6 +5,7 @@ const {
   entry,
   getMeetingById,
   getMeetingDetailById,
+  getMostConfirmedTime,
   closeMeeting,
   confirmTime,
 } = require('../controllers/meeting');
@@ -13,6 +14,8 @@ const router = express.Router();
 
 router.post('/', createMeeting);
 
+router.get('/most-confirmed-time', getMostConfirmedTime);
+
 router.post('/:meetingId/entry', entry);
 
 router.get('/:meetingId', isAuthenticated, getMeetingById);