Moustakas, who turned 31 in September, was a free agent for the third straight offseason after earning $18.7 million in a pair of one-year deals.
He hit .254 with 35 homers and 87 RBIs last season for the Milwaukee Brewers, earning his third All-Star selection. After starting the season at second base, he moved to third when Travis Shaw slumped.
The Reds plan to play Moustakas at second base.
Moustakas helped the 89-win Brewers overcome the early-September loss of 2018 MVP Christian Yelich and beat long odds to get back to the postseason for a second straight season, the first time they've done that since 1981 and '82. The Brewers went on to lose to the eventual World Series champion Washington Nationals in the National League wild-card game.
Moustakas had a $7 million salary in 2019 and received a $3 million buyout for declining his $10 million option for 2020.
He rejected a $17.4 million qualifying offer from the Kansas City Royals after the 2017 season and returned to the team for a one-year contract that included a $5.5 million salary and a $1 million option buyout. He was traded to the Brewers in July 2018 and finished with a .251 average, 28 homers and 95 RBIs, earning an additional $2.2 million in performance bonuses based on plate appearances.
He was instrumental in helping Kansas City reach the World Series twice, including its championship run in 2015. He brought that playoff experience to the Brewers as another power-hitting presence in the lineup and fell just one win short of a 2018 Series return.
Moustakas hit .364 in a three-game sweep of the Colorado Rockies in the 2018 NL Division Series. He had a game-ending two-out RBI single in the 10th inning in Game 1 and an RBI single in the eighth inning of Game 2 to help break open what had been a 1-0 game.
Moustakas has 182 homers, a .252 average and 561 RBIs in eight major league seasons.
The Reds also agreed with outfielder Travis Jankowski on a $1.05 million, one-year contract, avoiding salary arbitration.