Andrew McCutchen reached base four times, scored twice, and drove in a run for the Pirates, who extended their winning streak to five games.
Thomas Hatch opened the game for the Pirates and allowed three runs on three hits and a hit batter in 2 1/3 innings.
Cody Bolton (1-0), the fifth Pittsburgh pitcher, earned the victory. Closer David Bednar earned his 31st save.
Tyler O'Neill hit a three-run homer, Jordan Walker hit a two-run blast and Lars Nootbaar hit a solo shot for the Cardinals, who lost for the sixth time in eight games.
Cardinals starting pitcher Drew Rom allowed three runs on five hits and three walks in 4 2/3 innings. Drew VerHagen (4-1) took the loss.
The Cardinals moved ahead 3-0 in the second inning. Nolan Gorman singled, Hatch hit Willson Contreras with a pitch, then O'Neill hit his homer.
The Pirates cut their deficit to 3-1 in the fourth inning. McCutchen walked, moved to second on a passed ball, and scored on Connor Joe's triple.
Pittsburgh tied the game 3-3 in the fifth inning. Liover Peguero hit a leadoff single, Ke'Bryan Hayes drew a two-out walk, then Bryan Reynolds and McCutchen delivered RBI singles.
Nootbaar's homer put the Cardinals back on top 4-3 in the bottom of the inning.
The Pirates moved ahead 5-4 in the sixth inning. Endy Rodriguez walked, Miguel Andujar followed with an RBI double and Ji Hwan Bae hit a run-scoring single.
Tommy Edman led off the seventh inning with a single, then Walker followed with his homer to out the Cardinals back on top 6-5.
In the ninth inning, Verhagen hit McCutchen with a pitch and allowed Palacio's two-run homer that put Pittsburgh up 7-6.
Edman hit a single leading off the bottom of the inning. After Bednar hit Walker with a pitch, the runners advanced on a bunt.
But Bednar struck out Nootbaar and retired Paul Goldschmidt to close the victory.
—Field Level Media