Assuming as SQL Server, First, You can use the CTE to get rows from comma separated categories ids into rows, then using INNER JOIN on cat_id, you can get the desired result.
SEE DEMO SQL Server
;WITH CTEProduct (Product_name,category_id)
AS
(
SELECT A.Product_name,
Split.a.value('.', 'VARCHAR(100)') AS category_id
FROM
(
SELECT Product_name,
CAST ('<M>' + REPLACE(category_id, ',', '</M><M>') + '</M>' AS XML) AS Data
FROM Products
) AS A CROSS APPLY Data.nodes ('/M') AS Split(a)
)
Select CTEProduct.category_id,CTEProduct.Product_name,Categories.name
From CTEProduct
INNER JOIN Categories ON CTEProduct.category_id = Categories.cat_id
EDIT:- For MYSQL, we have to follow the same approach, convert comma separated string to multiple rows then INNER JOIN. I does not know much about How to separated comma separated string to rows in MYSQL so Refer Here. I utilized the same answer here.
SEE DEMO MYSQL
Select tablename.Product_name,GROUP_CONCAT(Categories.name) name
From (
SELECT Product_name,SUBSTRING_INDEX(SUBSTRING_INDEX(t.category_id, ',', n.n), ',', -1) category_id
FROM Products t CROSS JOIN
(
SELECT a.N + b.N * 10 + 1 n
FROM
(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a
,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b
ORDER BY n
) n
WHERE n.n <= 1 + (LENGTH(t.category_id) - LENGTH(REPLACE(t.category_id, ',', '')))
) tablename
INNER JOIN Categories ON tablename.category_id = Categories.cat_id
GROUP BY tablename.Product_name;